如何正确关闭 ODP.net 连接:dispose() 或 close()?
How to properly close ODP.net connection : dispose() or close()?
这是我的 powershell 代码:
[void][System.Reflection.Assembly]::LoadFile("C:\DLL\Oracle.ManagedDataAccess.dll")
$OracleConnexion = New-Object Oracle.ManagedDataAccess.Client.OracleConnection('User Id=test;Password="test";Data Source=10.2.2.1/TEST')
$TimeOut = 60
$OracleConnexion.Open()
$Query=$OracleConnexion.CreateCommand()
$Query.CommandText="Select * FROM TEST"
$Query.CommandTimeout = $Timeout
$ExecuteRequete=$Requete.ExecuteReader()
while ($ExecuteRequete.Read()) {
$SiebelLastRecord += $ExecuteRequete.GetDateTime(0).ToString()
}
$OracleConnexion.Close()
所以我打开 ODP.NET 与 $OracleConnexion.open()
的连接,然后用 $OracleConnexion.close()
关闭它是否足以正确关闭我与 Oracle 数据库的连接?还是我应该使用 $OracleConnexion.Dispose()
?
我通过任务调度程序每 5 分钟执行一次 powershell...所以也许我应该使用 Dispose() 来避免内存饱和吗?
Close 关闭连接并允许您重新打开它。
如果连接尚未关闭,Dispose 会关闭连接,同时也会将其处理掉,因此您无法再次打开它。
使用 dispose - dispose 释放资源的内存,
如果该资源已打开,则行为良好的 .dispose 方法将关闭该资源。
Dispose() vs. Close() with ConnectionPooling:
https://community.oracle.com/thread/165664?start=0&tstart=0
我会用 using 语句包装你的连接。完成连接后,请在添加支架之前将其关闭。为了 100% 安全,我会这样做:
using(OracleConnexion Con = new OracleConnection (...))
{
Con.Open()
...
Con.Close()
}
编辑:
我添加了 Con.Close()
,因为过去 dispose
在 ODP.NET 中没有正确实现。连接保持打开状态。我们必须手动强制关闭连接,这就是为什么在示例中我指定 Close
.
实现 IDisposable
的资源的更多标准实现是通过 using
:
包装它
using (OracleConnection connection = new OracleConnection(connectionString)){
using (OracleCommand command = new OracleCommand(sql, connection))
using (OracleDataReader reader = cmd.ExecuteReader())
{
}
connection.Close(); //optional
}
相当于执行块后执行.Dispose
。在内部,Dispose
也将处理关闭。不过,您也可以在命令块后调用 .Close()
。
oracle 文档中的 sample 使用 Oracle.DataAccess
也鼓励使用 Dispose
。
看起来和其他人一样,我很晚才注意到你在掌权shell。在那种情况下,这并不重要。 不管怎样,当 shell 结束时,一切都会被清理干净。我想你可以添加一个 [catch] 和 close/dispose 那里的连接,如果它仍然打开的话,但我认为只有当你计划让你的脚本继续时才有必要。
我将在下面留下冗长的 C# 答案。尽管它并不真正适用于您的脚本,但它解释了差异(或缺乏差异)。
简答(针对 c#):
using (var conn = new OracleConnection(connectionString))
{
}
"using" 确保 .Dispose 在块的末尾被调用,即使抛出异常也是如此。这样一来,您永远不会冒连接被孤立的风险,直到垃圾收集最终开始清理它,这可能是在您 运行 数据库连接中断之后。
长答案:
使用反射器,您会看到 Dispose 调用 Close:
protected override void Dispose(bool disposing)
{
if (ProviderConfig.m_bTraceLevelPublic)
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry);
this.m_disposed = true;
this.m_dataSource = string.Empty;
this.m_serverVersion = string.Empty;
try
{
bool flag = this.m_connectionState == ConnectionState.Closed && this.m_oracleConnectionImpl == null;
try
{
if (!disposing)
{
if (!flag)
{
if (OraclePool.m_bPerfNumberOfReclaimedConnections)
OraclePool.PerformanceCounterIncrement(OraclePerfParams.CounterIndex.NumberOfReclaimedConnections, this.m_oracleConnectionImpl, this.m_oracleConnectionImpl.m_cp);
}
}
}
catch (Exception ex)
{
if (ProviderConfig.m_bTraceLevelPublic)
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
}
if (!flag)
{
try
{
this.Close();
}
catch (Exception ex)
{
if (ProviderConfig.m_bTraceLevelPublic)
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
}
}
try
{
base.Dispose(disposing);
}
catch (Exception ex)
{
if (ProviderConfig.m_bTraceLevelPublic)
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
}
try
{
GC.SuppressFinalize((object) this);
}
catch (Exception ex)
{
if (!ProviderConfig.m_bTraceLevelPublic)
return;
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
}
}
catch (Exception ex)
{
if (!ProviderConfig.m_bTraceLevelPublic)
return;
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit);
}
}
有什么真正的区别吗?否 - 非托管资源是使用 .Close 处理的连接。如果您在 finally 块中检查连接状态并调用 .Close(如果它仍处于打开状态),您将看不到任何功能差异(除了延迟跟踪)。
OracleConnection conn = null;
try
{
conn = new OracleConnection(connectionString);
}
finally
{
if(conn.State != ConnectionState.Closed)
conn.Close();
}
也就是说,建议的一次性对象模式是使用 "using" 块。是的,我想您确实可以选择通过关闭重新打开连接,但我不认为这是一件有用的事情。
如果您没有使用 using 或 finally 并且抛出异常并且从未调用 close/dispose ,那么释放与数据库的连接将是不确定的 - Dispose(false) 会在任何时候发生垃圾收集器解决了这个问题——这可能在您 运行 失去与数据库的连接之后很久。
OracleConnection conn = null;
conn = new OracleConnection(connectionString);
conn.Open();
//exception occurs - Close is never called - resource leak!!
conn.Close();
这是我的 powershell 代码:
[void][System.Reflection.Assembly]::LoadFile("C:\DLL\Oracle.ManagedDataAccess.dll")
$OracleConnexion = New-Object Oracle.ManagedDataAccess.Client.OracleConnection('User Id=test;Password="test";Data Source=10.2.2.1/TEST')
$TimeOut = 60
$OracleConnexion.Open()
$Query=$OracleConnexion.CreateCommand()
$Query.CommandText="Select * FROM TEST"
$Query.CommandTimeout = $Timeout
$ExecuteRequete=$Requete.ExecuteReader()
while ($ExecuteRequete.Read()) {
$SiebelLastRecord += $ExecuteRequete.GetDateTime(0).ToString()
}
$OracleConnexion.Close()
所以我打开 ODP.NET 与 $OracleConnexion.open()
的连接,然后用 $OracleConnexion.close()
关闭它是否足以正确关闭我与 Oracle 数据库的连接?还是我应该使用 $OracleConnexion.Dispose()
?
我通过任务调度程序每 5 分钟执行一次 powershell...所以也许我应该使用 Dispose() 来避免内存饱和吗?
Close 关闭连接并允许您重新打开它。
如果连接尚未关闭,Dispose 会关闭连接,同时也会将其处理掉,因此您无法再次打开它。
使用 dispose - dispose 释放资源的内存, 如果该资源已打开,则行为良好的 .dispose 方法将关闭该资源。
Dispose() vs. Close() with ConnectionPooling: https://community.oracle.com/thread/165664?start=0&tstart=0
我会用 using 语句包装你的连接。完成连接后,请在添加支架之前将其关闭。为了 100% 安全,我会这样做:
using(OracleConnexion Con = new OracleConnection (...))
{
Con.Open()
...
Con.Close()
}
编辑:
我添加了 Con.Close()
,因为过去 dispose
在 ODP.NET 中没有正确实现。连接保持打开状态。我们必须手动强制关闭连接,这就是为什么在示例中我指定 Close
.
实现 IDisposable
的资源的更多标准实现是通过 using
:
using (OracleConnection connection = new OracleConnection(connectionString)){
using (OracleCommand command = new OracleCommand(sql, connection))
using (OracleDataReader reader = cmd.ExecuteReader())
{
}
connection.Close(); //optional
}
相当于执行块后执行.Dispose
。在内部,Dispose
也将处理关闭。不过,您也可以在命令块后调用 .Close()
。
oracle 文档中的 sample 使用 Oracle.DataAccess
也鼓励使用 Dispose
。
看起来和其他人一样,我很晚才注意到你在掌权shell。在那种情况下,这并不重要。 不管怎样,当 shell 结束时,一切都会被清理干净。我想你可以添加一个 [catch] 和 close/dispose 那里的连接,如果它仍然打开的话,但我认为只有当你计划让你的脚本继续时才有必要。
我将在下面留下冗长的 C# 答案。尽管它并不真正适用于您的脚本,但它解释了差异(或缺乏差异)。
简答(针对 c#):
using (var conn = new OracleConnection(connectionString))
{
}
"using" 确保 .Dispose 在块的末尾被调用,即使抛出异常也是如此。这样一来,您永远不会冒连接被孤立的风险,直到垃圾收集最终开始清理它,这可能是在您 运行 数据库连接中断之后。
长答案:
使用反射器,您会看到 Dispose 调用 Close:
protected override void Dispose(bool disposing)
{
if (ProviderConfig.m_bTraceLevelPublic)
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry);
this.m_disposed = true;
this.m_dataSource = string.Empty;
this.m_serverVersion = string.Empty;
try
{
bool flag = this.m_connectionState == ConnectionState.Closed && this.m_oracleConnectionImpl == null;
try
{
if (!disposing)
{
if (!flag)
{
if (OraclePool.m_bPerfNumberOfReclaimedConnections)
OraclePool.PerformanceCounterIncrement(OraclePerfParams.CounterIndex.NumberOfReclaimedConnections, this.m_oracleConnectionImpl, this.m_oracleConnectionImpl.m_cp);
}
}
}
catch (Exception ex)
{
if (ProviderConfig.m_bTraceLevelPublic)
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
}
if (!flag)
{
try
{
this.Close();
}
catch (Exception ex)
{
if (ProviderConfig.m_bTraceLevelPublic)
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
}
}
try
{
base.Dispose(disposing);
}
catch (Exception ex)
{
if (ProviderConfig.m_bTraceLevelPublic)
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
}
try
{
GC.SuppressFinalize((object) this);
}
catch (Exception ex)
{
if (!ProviderConfig.m_bTraceLevelPublic)
return;
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
}
}
catch (Exception ex)
{
if (!ProviderConfig.m_bTraceLevelPublic)
return;
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit);
}
}
有什么真正的区别吗?否 - 非托管资源是使用 .Close 处理的连接。如果您在 finally 块中检查连接状态并调用 .Close(如果它仍处于打开状态),您将看不到任何功能差异(除了延迟跟踪)。
OracleConnection conn = null;
try
{
conn = new OracleConnection(connectionString);
}
finally
{
if(conn.State != ConnectionState.Closed)
conn.Close();
}
也就是说,建议的一次性对象模式是使用 "using" 块。是的,我想您确实可以选择通过关闭重新打开连接,但我不认为这是一件有用的事情。
如果您没有使用 using 或 finally 并且抛出异常并且从未调用 close/dispose ,那么释放与数据库的连接将是不确定的 - Dispose(false) 会在任何时候发生垃圾收集器解决了这个问题——这可能在您 运行 失去与数据库的连接之后很久。
OracleConnection conn = null;
conn = new OracleConnection(connectionString);
conn.Open();
//exception occurs - Close is never called - resource leak!!
conn.Close();