背景:我正在将使用MS Access进行数据存储的VB6应用程序重写为使用VB.NET和MS SQL Server的应用程序。
我很好奇在我的应用程序中需要连接到数据库的不同表单之间传递连接的最佳方法。现在我已经构建了一个类来管理连接字符串,以便以安全的方式在表单之间传递:
Public Class LoginCredientials Private uname As String Private password_hash() As Byte = {0} Private server_name As String 'not used in access style databases Private dbname As String Private st As ServerType 'enum that would allow for different connections Private tdes As TripleDES 'encryption class to encrypt password in memory Public Sub New() uname = "" server_name = "" dbname = "" st = ServerType.stNotDefined End Sub Public Sub New(ByVal Username As String, _ ByVal Password As String, _ ByVal ServerName As String, _ ByVal DatabaseName As String, _ ByVal ServType As ServerType) tdes = New TripleDES uname = Username password_hash = tdes.Encrypt(Password) server_name = ServerName dbname = DatabaseName st = ServType tdes = Nothing End Sub Public ReadOnly Property Server_Type() As ServerType Get Return st End Get End Property Public ReadOnly Property CompanyName() As String Get Return dbname.Remove(0, 4) End Get End Property Public Property UserName() As String Get Return uname End Get Set(ByVal value As String) uname = value End Set End Property Public Property Password() As String Get tdes = New TripleDES Return tdes.Decrypt(password_hash) tdes = Nothing End Get Set(ByVal value As String) tdes = New TripleDES password_hash = tdes.Encrypt(value) tdes = Nothing End Set End Property Public Property ServerName() As String Get Return server_name End Get Set(ByVal value As String) server_name = value End Set End Property Public Property DatabaseName() As String Get Return dbname End Get Set(ByVal value As String) dbname = value End Set End Property Public Function GetConnectionString() As String Dim cstring As String = "" tdes = New TripleDES Select Case st Case ServerType.stSQLServer cstring = "User ID=" & uname & ";" & _ "Password=" & tdes.Decrypt(password_hash) & ";" & _ "Initial Catalog=" & dbname & ";" & _ "Data Source=" & server_name End Select tdes = Nothing Return cstring End Function End Class
我一直在将对象的引用传递给需要连接到数据库的任何表单,如下所示:
'in the form declaration Private myLC As LoginCredientials Public Sub New(ByRef lc As LoginCredientials) InitializeComponent() myLC = lc End Sub
然后我会创建一个新的连接对象,做我需要做的事情,然后关闭连接并销毁连接对象。当我很久以前在ADO中使用VB6完成此操作时,连接创建的进程在连接对象被销毁时被终止,但这似乎不再是这种情况了。现在,每次创建新的连接对象并连接到我的服务器时,都会创建一个新进程,然后在关闭连接时进入休眠状态。一段时间后,服务器将开始拒绝连接,直到我登录并终止我的应用程序创建的所有进程。显然这不是正确的,我想学习正确的方法。
在表单中简单地通过引用(或在包装类中)传递相同的连接对象,让连接对象保持打开状态会更好吗?
关闭连接的正确方法是什么,以便最终我的SQL服务器上没有一堆休眠进程? SQL服务器中是否有设置我可以调整以在一段时间不活动后自动终止进程?
您是否会考虑在运行时内存过度加密密码?
感谢您的帮助。 :)
答案 0 :(得分:8)
您 不应该 在表单之间传递连接对象。基本上,使用SQL Server连接时的模式是创建连接,打开它,执行操作,然后关闭连接。
为此,你应该在某个地方有一个公共静态方法,它将生成你将在Using语句中使用的SqlConnection,如下所示:
Using connection As SqlConnection = GetConnection
' Use connection here.
End Using
这应该可以防止进程在服务器上堆叠。
答案 1 :(得分:1)
您可以使用Using语句,它将在完成后关闭并处理连接。
Using _conn as New SqlConnection(<connstring>)
_conn.Open()
'get your data'
End Using
如果你没有调用.Close(),那可能就是问题了。
答案 2 :(得分:1)
我同意卡斯帕。如果您确实需要在页面之间共享对象以减少负载,那么您可以使用静态成员变量来执行此操作。只需确保在执行最后一个语句时关闭连接。您还可以创建一个可在最后一个事务完成时处置的连接范围。如果您没有这方面的经验,那么只需尽早打开和关闭您的连接,不要传递它。
我有一个网络应用程序,为了减少一些延迟,有些情况下我使用我为DAL创建的作用域,这样如果在子函数中有调用它们可以使用相同的连接而不会被提升到MSDTC。然而,这实际上只在交易系统中是必要的。
答案 3 :(得分:1)
正如您正在使用的VB.NET,请尝试此操作(代码来自内存,而不是从应用程序复制):
Namespace Helpers
Public NotInheritable Class Connections
Private Sub New()
End Sub
Public Shared Function GetConnection(ByVal connString As String) As SqlConnection
Dim c as New SqlConnection(connString)
c.Open
Return c
End Sub
Public Shared Sub AdoCleanup(cn As SqlConnection, cmd As SqlCommand)
cmd.Dispose
cn.Close
End Sub
End Class
End Namespace
然后像这样使用它:
Private Sub LoadMyData()
Dim connString As String = <your conn string>
Dim cn As SqlConnection = Helpers.Connections.GetConnection(connString)
Dim cmd As New SqlCommand
Try
' data access code
Catch ex As Exception
' handle exception
Finally
Helpers.Connections.AdoCleanup(cn, cmd)
End Try
End Sub
除非您需要灵活地使用不同的连接字符串打开多个连接,否则您甚至可以将代码放入GetConnection中来获取连接字符串。
答案 4 :(得分:0)
从不通过连接。
我通常要做的是,创建一个主控制器,每个控制器都从该主控制器继承该主控制器,并在该连接上定义。 然后每当我启动一个连接对象时,我都会使用(使用)。