带有 DbTransactions 的 DbDataReader
将 DbDataReader 与 DbTransactions 结合使用是错误的方式还是缺乏性能?代码示例:
public DbDataReader ExecuteReader()
{
try
{
if (this._baseConnection.State == ConnectionState.Closed)
this._baseConnection.Open();
if (this._baseCommand.Transaction != null)
return this._baseCommand.ExecuteReader();
return this._baseCommand.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (Exception excp)
{
if (this._baseCommand.Transaction != null)
this._baseCommand.Transaction.Rollback();
this._baseCommand.CommandText = string.Empty;
this._baseConnection.Close();
throw new Exception(excp.Message);
}
}
某些方法调用此操作。有时打开 DbTransaction。它使用 DbConnection 和 DbCommand。
真正的问题是在生产环境中(例如每天 5,000 次访问),ADO 操作开始抛出异常
它有一个方法,不会打开 DbTransaction,但无论如何都会抛出 excp。
编辑:我们实现了日志来分析 ADO 操作。这是在生产环境中捕获 ADO 问题的一种方法。捕获的异常是:
已经有一个与此命令关联的打开的 DataReader,必须先将其关闭。
阅读器关闭时调用 Read 的尝试无效。
连接未关闭。连接的当前状态为打开。
另外,我们意识到 dbHelper 类是这样实例化的:
private static readonly dbHelper<T> _instance = new dbHelper<T>();
public static dbHelper<T> GetInstance()
{
return _instance;
}
DAO 的构造函数实例化 dbHelper:
this._dataPersist =
Registro.Classes.dbHelper<System.Data.SqlClient.SqlClientFactory>.GetInstance();
我们认为更改数据访问代码,用另一种方法替换通用 dbHelper 可能会解决问题。任何建议将不胜感激。
Its the wrong way or lack of performance, using DbDataReader combinated with DbTransactions? An example of code:
public DbDataReader ExecuteReader()
{
try
{
if (this._baseConnection.State == ConnectionState.Closed)
this._baseConnection.Open();
if (this._baseCommand.Transaction != null)
return this._baseCommand.ExecuteReader();
return this._baseCommand.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (Exception excp)
{
if (this._baseCommand.Transaction != null)
this._baseCommand.Transaction.Rollback();
this._baseCommand.CommandText = string.Empty;
this._baseConnection.Close();
throw new Exception(excp.Message);
}
}
Some methods call this operation. Sometimes openning a DbTransaction. Its using DbConnection and DbCommand.
The real problem, is in production enviroment (like 5,000 access/day) the ADO operations start throwing exceptions
It has an method, that doesnt open a DbTransaction, but throws the excp anyway.
EDIT: We implemented log, to analyse ADO operations. This was an approach to catch the ADO problems in production enviroment. The exceptions caught were:
There is already an open DataReader associated with this Command which must be closed first.
Invalid attempt to call Read when reader is closed.
The connection was not closed. The connection's current state is open.
Also, we realized that the dbHelper class, is instantiated this way:
private static readonly dbHelper<T> _instance = new dbHelper<T>();
public static dbHelper<T> GetInstance()
{
return _instance;
}
And the DAO's constructors, instatiate the dbHelper:
this._dataPersist =
Registro.Classes.dbHelper<System.Data.SqlClient.SqlClientFactory>.GetInstance();
We think changing the data access code, replacing the generic dbHelper with another approach, might fix the problem. Any suggestions would be appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一个潜在的问题是 DbTransaction、DbConnection 及其同类都是抽象类。在某些时候,您需要提供这些类型的真正具体实现。虽然这让我觉得编译器会捕获一些东西,但我认为它仍然值得一提。
更有可能的是,您将连接保持打开状态的时间过长。阅读你的粗体句子,我留下的印象是生产代码最初不会抛出异常。只有在运行一段时间后才会出现例外情况。这也与您发布的代码相匹配,因为就在您的小型共享代码中,我已经看到两个地方您的代码没有正确清理其资源。
您的执行读取器函数不会关闭基础如果在回滚事务时抛出异常,则连接。此外,您在问题末尾发布的代码片段可能无法正确关闭阅读器。处置资源的正确方法是使用 using 块,如下所示:
请注意,无需调用 Close() 或 Dispose() 方法。 using 块会为您处理这件事,即使抛出异常,它也会这样做。
One potential issue is that DbTransaction, DbConnection, and their ilk are all abstract classes. At some point you need to provide real concrete implementations of those types. This strikes me as something the compiler would catch,though, but I thought it was still worth mentioning.
More likely it's that you're leaving connections open for too long. Reading your bold sentence, I'm left with the impression that the production code does not throw exceptions initially. The exceptions only come after you've left it running a little while. That matches with the code you posted, too, because just in your small shared code I already see two places where your code doesn't clean up it's resources correctly.
Your execute reader function will not close the base connection if an exception is thrown while rolling back a transaction. Additionally, the snippet you posted at the end of your question may not properly close the reader. The correct way to dispose of your resources is with a using block, like this:
Note that there is no need to call the Close() or Dispose() method. The using block takes care of that for you, and it does it even if an exception is thrown.