在記憶體回收 Microsoft Visual Basic 6.0 和 Microsoft Visual Basic.NET 之間的差異
在 Visual Basic 6.0 和 Visual Basic.NET 記憶體回收之間有主要的差異。主要的差異在於 Visual Basic 6.0 中的記憶體回收是更積極比 Visual Basic.NET 記憶體回收。與 Visual Basic 6.0 一旦物件執行個體超出範圍,會立即釋放物件。與 Visual Basic.NET 或一般.NET 記憶體回收,就不會發生相同的行為。與.NET 記憶體回收集合物件是以非同步的方式發行。
記憶體回收的差異呈淚您的資料存取程式碼上大型的效果,當您從 Visual Basic 6.0 中移至 Visual Basic.NET 時。
比方說,當物件回收由記憶體回收就關閉開啟 ADODB
資料錄集 物件。開發人員有經驗撰寫 Visual Basic 6.0 中的程式碼可能會依賴它們遷移到 Visual Basic.NET 的程式碼時,會改變的記憶體回收集合語意。因為.NET 記憶體回收是非同步和不具決定性,您可能無法看到所做的變更,即使基本測試就會發生。
如 Microsoft SQL Server 2000 資料庫的某些資料庫只支援單一使用中結果集,每個連線。如果您有 Firehose 指標開啟在連線到 SQL Server 連線會被封鎖,直到資料指標關閉為止。依預設值,OLE DB 提供者將會開啟額外的連線執行查詢,如果目前的連線無法執行該查詢。因此,許多 ActiveX 資料物件 (ADO) 使用者都不知道這項限制。這些額外的連線不會參與連接共用。開啟額外的連線時封鎖的連線參與交易的嘗試會失敗。
我們建議您檢閱您的 Visual Basic 6.0 中程式碼,並明確的關閉所有的
資料錄集 物件和連線。您的程式碼遷移至 Visual Basic.NET 後,然後,重新測試程式碼。
本節列出這個問題的三個範例和每個範例的程式碼範例。
範例 1: 其他連線開啟時您並不會明確地關閉資料錄集物件
在 Visual Basic 6.0 中執行下列程式碼範例時, 就需要只有一個單一的連線。因為當
資料錄集 物件超出範圍時隱含地關閉所
ExecuteQuery 程序中建立的
資料錄集 物件也是如此。 程式碼範例會使用 SQL Server @ @ SPID 變數來代表伺服器處理序識別項,用來執行查詢。 如果您在執行程式碼您會注意到查詢傳回相同的值在
@ @ spid 資料行。這個結果表示查詢被執行相同的連線上資料庫
Public Sub Main()
Dim strConn As String
Dim cn As ADODB.Connection
strConn = "Provider=SQLOLEDB;Data Source=.;" & _
"Initial Catalog=Northwind;Trusted_Connection=Yes;"
Set cn = New ADODB.Connection
cn.Open strConn
cn.Properties("Multiple Connections").Value = False
ExecuteQuery cn, "SELECT @@spid, * FROM Customers"
ExecuteQuery cn, "SELECT @@spid, * FROM Customers"
End Sub
Private Sub ExecuteQuery(cn As ADODB.Connection, strSQL As String)
Dim rs As ADODB.Recordset
Set rs = cn.Execute(strSQL)
MsgBox rs(0)
End Sub
如果您在中 Visual Basic.NET 使用類似的程式碼您會注意到第二個
資料錄集 物件包含
@ @ spid 的不同值 資料行。這個值表示查詢已執行不同的連線至資料庫。
這項行為是不同的因為
ExecuteQuery 程序中所建立的
資料錄集 物件未關閉,而且會保持開啟,直到.NET 記憶體回收行程清除
資料錄集 物件。 在 Microsoft.NET Framework 的記憶體回收就會以非同步方式發生。如果不
ExecuteQuery 程序會再次呼叫的時間已關閉
資料錄集 物件,SQL Server OLE DB 提供者將會開啟新的連線,執行第二個查詢。
如果在
ExecuteQuery 程序中新增
rs.Close 命令的呼叫您要確定相同的連線上會執行查詢。 您可以也明確告訴 SQL Server OLE DB 提供者不來開啟其他連接。若要執行此動作加入在下列程式碼行的程式碼在開啟連線之後立刻:
cn.Properties("Multiple Connections").Value = False 這個程式碼會讓 SQL Server OLE DB 提供者擲回例外狀況,每次 OLE DB 提供者否則會開啟額外的連線。
範例 2: 問題時,會發生您使用交易如果您不執行明確關閉資料錄集物件
封鎖的連線參與交易時,無法開啟額外的連線。 在 Visual Basic 6.0 中執行下列程式碼範例時,程式碼會在單一連接已開啟的交易上執行多個查詢。 程式碼會呼叫下列兩個功能:
每個函式會開啟
資料錄集 物件
Public Sub Main()
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
cn.Open "Provider=SQLOLEDB;Data Source=.;" & _
"Initial Catalog=Northwind;Trusted_Connection=Yes;"
cn.BeginTrans
GetCustomers cn
GetOrders cn
cn.RollbackTrans
cn.Close
End Sub
Public Sub GetCustomers(Connection As ADODB.Connection)
Dim rs As ADODB.Recordset
Set rs = Connection.Execute("SELECT CustomerID, CompanyName FROM Customers")
End Sub
Public Sub GetOrders(Connection As ADODB.Connection)
Dim rs As ADODB.Recordset
Set rs = Connection.Execute("SELECT OrderID, CustomerID FROM Orders")
End Sub
所藉由呼叫
GetCustomers 函式建立的
資料錄集 物件隱含關閉在 Visual Basic 6.0 中該函式呼叫的結尾。這種行為將會說明"範例 1: 其他連線開啟時您並不會明確地關閉資料錄集物件 」 區段。不過,該
資料錄集 物件可能不會關閉依您的程式碼在 Visual Basic.NET 呼叫
GetOrders 函式的時間。因此,目前連線到 SQL Server 有開啟的結果集,客戶資訊。因為目前的連線忙碌所以擷取
GetOrders 函式中查詢結果需要新的隱含建立連線。但是,您無法建立隱含的連接,只要是開啟的交易。因此,程式碼將會失敗,並且您會收到下列錯誤訊息:
若要解決這個問題,明確關閉使用
GetCustomers] 和 [
GetOrders 函式所建立的
資料錄集 物件。
範例 3: 問題時,會發生您隱含建立,並放棄資料錄集物件
預設情況下,
Execute 方法的
連線] 及 [
指令] 物件會隱含建立,並傳回新的
資料錄集 物件。 在 Visual Basic 6.0 中如果此
資料錄集 物件不物件變數在維護
資料錄集 物件超出範圍,並將立即關閉。 因此,下列程式碼範例成功地在執行 Visual Basic 6.0 中。但是,您將會收到錯誤訊息中所提到"範例 2: 當您使用交易如果您不執行明確關閉資料錄集物件時,就會發生問題 」 區段如果程式碼移轉到 Visual Basic.NET
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
cn.Open "Provider=SQLOLEDB;Data Source=.;" & _
"Initial Catalog=Northwind;Trusted_Connection=Yes;"
cn.BeginTrans
cn.Execute "SELECT CustomerID, CompanyName FROM Customers"
cn.Execute "SELECT OrderID, CustomerID FROM Orders ORDER BY CustomerID"
cn.RollbackTrans
cn.Close
在這個程式碼] 範例
Execute 方法的
連線 物件的呼叫隱含地傳回
資料錄集 物件。在 Visual Basic 6.0 中的記憶體回收立即關閉每個
資料錄集 物件,因為傳回的值不儲存在變數中。無法侵略性的在 Visual Basic.NET 記憶體回收。
資料錄集 物件,其中包含客戶資訊仍為開啟狀態時呼叫查詢資料庫中的訂單資訊,就會發生。您收到錯誤訊息中所提到的因此,"範例 2: 當您使用交易如果您不執行明確關閉資料錄集物件時,就會發生問題 」 區段。
若要解決這個問題,傳遞從
ExecuteOptionsEnum 值
選項 參數的
Execute 方法中的 [
adExecuteNoRecords 值]。當您執行這項操作時可以指出
Execute 方法不應傳回一個
資料錄集 物件如所示
cn.Execute "SELECT CustomerID, CompanyName FROM Customers", , _
ADODB.ExecuteOptionsEnum.adExecuteNoRecords
,下列程式碼範例。
問題 2: 我們不建議 ADODB PIA 壓力案例
我們強烈防止您從使用 ADODB PIA 壓力案例下例如,在多使用者的 Microsoft ASP.NET 或 Microsoft COM + 元件。 當 Microsoft 測試團隊進行測試 ADODB PIA 時,測試小組會找到 ADODB PIA 失敗壓力之下。 如果.NET 資料存取程式碼必須可靠地在強大壓力下執行,我們強烈建議您在使用 ADO.NET 來撰寫程式碼。
問題 3: 我們不建議您在 64 位元模式使用 ADODB PIA
我們強烈防止您無法在 64 位元應用程式中使用 ADODB PIA。 ADODB PIA 尚未經過測試在 64 位元模式。 大多數的 64 位元案例牽涉到如 ASP.NET 或 COM + 高壓力伺服器端元件。 ADODB PIA 有已知問題在壓力下執行。64 位元模式較少使用 ADODB PIA 的嶄新,也可以讓有限的可用性的 64 位元 OLE DB 提供者。
問題 4: 失敗當您使用就會發生晚期繫結查詢執行
ADODB 支援兩種形式的晚期繫結查詢執行。執行晚期繫結查詢可讓您在 COM 中使用
IDispatch 繫結執行查詢,查詢就像
連線 物件上的方法。ADODB 支援兩種晚期繫結查詢執行下列形式:
- 若要建立 「 具名 」 查詢設定 Command 物件的 [名稱] 屬性。
- 執行預存程序呼叫。
當您將程式碼從 Visual Basic 6.0 中移轉到 Visual Basic.NET 時,可能會遇到這些表單的問題。
下列範例說明這些問題。
範例 1: 如果您建立具有相同名稱的第二個晚期繫結查詢時,會查詢失敗
下列的程式碼範例會建立兩個
命令 物件的 [
名稱] 屬性使用相同的值的晚期繫結查詢
Dim cn As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim strConn As String
'Open a new Connection.
strConn = "Provider=SQLOLEDB;Data Source=.;" & _
"Initial Catalog=Northwind;Trusted_Connection=Yes"
Set cn = New ADODB.Connection
cn.Open strConn
'Create a Command object, and then set the Name property
'to enable the Command object as a late-bound method call.
Set cmd = New ADODB.Command
cmd.CommandText = "SELECT COUNT(*) FROM Customers"
cmd.Name = "GetCount"
Set cmd.ActiveConnection = cn
'Execute the Command object as a late-bound method call on the Connection.
Set rs = New ADODB.Recordset
cn.GetCount rs
Debug.Print rs(0).Value
rs.Close
Set rs = Nothing
'Release the Command object.
Set cmd = Nothing
'Create a new Command object, and then set the Name property
'to enable the Command object as a late-bound method call.
Set cmd = New ADODB.Command
cmd.CommandText = "SELECT COUNT(*) FROM Orders"
cmd.Name = "GetCount"
Set cmd.ActiveConnection = cn
'Execute the Command object as a late-bound method call on the Connection object.
Set rs = New ADODB.Recordset
cn.GetCount rs
Debug.Print rs(0).Value
rs.Close
Set rs = Nothing
'Clean up.
cn.Close
Visual Basic 6.0 中只要
命令 物件設定為 Nothing,物件會回收由記憶體回收。
連線 物件會被通知
Command 物件已被摧毀。 因此,第二個
命令 物件與
連線 物件相關聯時,沒有衝突存在。
在 Visual Basic.NET 中執行類似的程式碼時,
Command 物件可能不回收由記憶體回收,由第二個
命令 物件是與
連線 物件相關聯的時間。因此,可能會收到下列的例外狀況錯誤訊息:
如果要解決這個問題,您必須以手動方式解除關聯第一個
命令 物件從
連線 物件。若要執行此動作明確地呼叫
cmd.ActiveConnection 方法時清除
命令 物件。如果要執行這項操作,使用
'Visual Basic 6.0 syntax
Set cmd.ActiveConnection = Nothing
'Visual Basic .NET syntax
cmd.ActiveConnection = Nothing
下列程式碼範例。
範例 2: 如果您在第二個連線上呼叫晚期繫結查詢,會查詢失敗
下列程式碼範例會執行下列工作,它們依照的順序:
- 建立兩個 連線 物件。
- 在每個 連線 物件上建立 命令 物件。每個 命令 物件都有 名稱 屬性的值相同。
- 利用晚期繫結查詢執行執行每個命令。
Dim strConn As String, strSQL As String
Dim cn1 As ADODB.Connection, cn2 As ADODB.Connection
Dim cmd1 As ADODB.Command, cmd2 As ADODB.Command
Dim rs1 As ADODB.Recordset, rs2 As ADODB.Recordset
strConn = "Provider=SQLOLEDB;Data Source=.;" & _
"Initial Catalog=Northwind;Trusted_Connection=Yes;"
strSQL = "SELECT COUNT(*) FROM Customers"
'Open connections.
Set cn1 = New ADODB.Connection
Set cn2 = New ADODB.Connection
cn1.Open strConn
cn2.Open strConn
'Create commands so that the commands can be executed as late-bound methods.
Set cmd1 = New ADODB.Command
Set cmd2 = New ADODB.Command
cmd1.CommandText = strSQL
cmd2.CommandText = strSQL
cmd1.Name = "GetCount"
cmd2.Name = "GetCount"
Set cmd1.ActiveConnection = cn1
Set cmd2.ActiveConnection = cn2
'Execute queries as late-bound methods.
Set rs1 = New ADODB.Recordset
Set rs2 = New ADODB.Recordset
cn1.GetCount rs1
cn2.GetCount rs2
MsgBox rs1(0).Value
MsgBox rs2(0).Value
'Clean up.
rs1.Close
rs2.Close
cn1.Close
cn2.Close
當您使用 Visual Basic 6.0 中,這個程式碼範例就會成功。不過,這個程式碼範例會失敗,當您使用 Visual Basic.NET。這項失敗發生的原因,是因為以下原因:
- ADODB 準備這些查詢做為晚期繫結方法的方式
- Visual Basic.NET 編譯器進行有關這些方法的假設
當您設定的
命令 物件
ActiveConnection 屬性時,ADODB 會檢查
命令 物件是否具有 [
名稱] 屬性設定。如果
名稱 屬性設定,ADODB 會準備查詢,以便為晚期繫結方法,
連線 物件上執行查詢。在此範例將兩個
命令 物件會有
CommandText 屬性的值相同。不過,這是非常簡化的範例。雖然
命令 物件有
名稱 屬性的值相同,
命令 物件可能有
CommandText 值會執行非常不同的查詢。因此,ADODB 會產生唯一的方法簽名碼為晚期繫結方法。
Visual Basic.NET 編譯器並不會讓此區分。上 GetCount 」 查詢的第一次呼叫,Visual Basic.NET 編譯器會快取方法簽名碼,以防
GetCount 方法
連線 物件上進行另一個呼叫。當程式碼會呼叫第二個 GetCount 」 查詢時,Visual Basic.NET 就會重複使用快取的方法簽名碼的第二個
GetCount 方法。因為 ADODB 會產生唯一的方法簽名碼,到第二個晚期繫結查詢呼叫會失敗。
沒有因應措施存在於此案例中。
問題 5: 可以設定一些 ADODB Variant 資料型別到字串資料型別
ADODB 物件模型可讓您設定某些屬性為字串,或是其他 ADODB 物件。比方說
資料錄集 物件的
ActiveConnection 屬性會出現在 Visual Basic 6.0 物件瀏覽器為 Variant 資料型別,並且可以被設定成
連線 物件或連接字串。
如果您已經建立您自己的物件,且想要支援這項功能,您必須建立個別的屬性存取子。如果要執行這項操作,使用類似下列程式碼範例的程式碼的程式碼
Public Property Let ActiveConnection (ByVal value As String)
'Add logic here.
End Property
Public Property Set ActiveConnection (ByRef value As Object)
'Add logic here.
End Property
的.NET Framework 是有點更嚴格,而且不允許為使用不同資料型別的多個屬性存取子。ADODB PIA 可讓您將
資料錄集 物件的
ActiveConnection 屬性設定為
連線 物件。如果想將
ActiveConnection 屬性設定為一字串您就必須使用
let_ActiveConnection 方法,如下列程式碼範例所示
Dim strConn As String
Dim rs As ADODB.Recordset
strConn = "Provider=SQLOLEDB;Data Source=.;" & _
"Initial Catalog=Northwind;Trusted_Connection=Yes;"
rs = New ADODB.Recordset
rs.let_ActiveConnection(strConn)
相同的方法時,需要您設定下列屬性:
- 資料錄集 物件的 [資料來源] 屬性
- 命令 物件的 ActiveConnection 屬性
這些屬性接受物件。若要設定這些屬性為字串,您必須使用對應的
let_ MethodName 方法。
當問題 6: 一個 InvalidCastException 時,就會發生例外狀況呼叫 Parameters.Append 方法
ADODB PIA 隨附於 Microsoft Visual Studio.NET 2003年與 Visual Studio 2005 具有當您呼叫
Parameters.Append 方法一起使用預設的建構函式所建立的一個
參數 物件時所發生的已知的問題。
下列程式碼範例會造成
InvalidCastException 例外狀況
Dim cmd As ADODB.Command
Dim p As ADODB.Parameter
cmd = New ADODB.Command
cmd.CommandText = "SELECT CustomerID FROM Orders WHERE OrderID = ?"
p = New ADODB.Parameter
p.Name = "@OrderID"
p.Type = ADODB.DataTypeEnum.adInteger
p.Value = 10248
cmd.Parameters.Append(p)
若要解決這個問題,
參數 物件使用建立的
指令 的物件
CreateParameter 方法如下列程式碼範例所示
Dim cmd As ADODB.Command
Dim p As ADODB.Parameter
cmd = New ADODB.Command
cmd.CommandText = "SELECT CustomerID FROM Orders WHERE OrderID = ?"
p = cmd.CreateParameter()
p.Name = "@OrderID"
p.Type = ADODB.DataTypeEnum.adInteger
p.Value = 10248
cmd.Parameters.Append(p)
您遇到問題處理元件預期 ADO 2.8 介面的問題 7:
ADODB PIA 隨附於 Visual Studio 2005 是相同的元件,是隨附在 Visual Studio.NET 2003年,並且藉由使用 Microsoft.NET Framework 1.1 已建置。ADODB PIA 互動,ADO 2.7 介面而建立,且尚未更新若要使用 ADO 2.8 介面。
因此,使用 ADODB PIA 搭配 ADO 2.8 介面會公開 (Expose) 的元件的嘗試失敗。 這種情況下不支援具有 ADODB PIA。