.NET 5 System.Data连接池疑问:高层封装类的连接复用
.NET 5数据库连接池相关疑问解答
我上午研究了.NET 5的System.Data数据库连接池,了解到其默认启用,由应用/系统自动处理。因刚接触数据库访问与连接池,针对自己编写的高层数据库抽象类(代码如下),有以下疑问:
public abstract class AbstractDatabase<T> where T : System.Data.Common.DbConnection { // Take this class's connection string and return a new connection object public abstract T GetConnection(); public abstract SqlKata.Compilers.Compiler Compiler { get; } // Compile the query and return a DataTable // This is actually pointing to a static method that uses the IDBConnection interface and logs any errors, but I copied the relavant code here public virtual DataTable GetDataTable(SqlKata.Query query) { using (var Conn = GetConnection()) { if (Conn.State == ConnectionState.Closed) Conn.Open(); using (var Cmd = Conn.CreateCommand()) { Cmd.CommandType = CommandType.Text; Cmd.Connection = Conn; Cmd.CommandText = Compiler.Compile(query).ToString(); // the query is fully formed string here Cmd.Parameters.AddDummyParameter(); // I noticed that without any parameters, this didn't work, so this method adds a dummy, even if the string doesn't have any '?' characters using (var DR = Cmd.ExecuteReader()) { DataTable DT = new DataTable(); DT.Load(DR); return DT; } } } } } public class SomeDatabase : AbstractDatabase<OleDbConnection> { // class implementation }
疑问列表
- 若多次调用
SomeDatabase.GetDataTable(),方法内using会自动释放连接,连接池会立即复用该连接吗? - 如下写法是否有意义?
using ( var conn = SomeDatabase.GetConnection()) { DataTable Tbl1 = SomeDatabase.GetDataTable(Query1); .... DataTable Tbl10 = SomeDatabase.GetDataTable(Query10); }
- 该写法与原有写法有区别吗?是否应让方法接受已打开的连接?是否应让类复用单个连接对象?
解答
问题1
当using块结束时,连接会被释放(并非销毁),此时连接池会将该连接标记为可用状态,可以立即被复用。需要注意:连接池复用连接的前提是连接的连接字符串、身份验证信息等完全匹配,且连接本身未出现异常或损坏。另外,调用Conn.Open()时,连接池会优先尝试从池中获取可用连接,无可用连接时才会新建。
问题2
这种写法没有意义。你在using块中创建的conn对象并未被GetDataTable()方法使用——GetDataTable()内部会自行调用GetConnection()创建新连接,与外部的conn完全无关。外部的conn最终会被using释放,但对内部10次查询没有任何实际作用。
问题3
- 写法区别:原有写法每次调用
GetDataTable()都会创建并释放一个连接(实际是归还到连接池);你写的这种写法额外创建了一个完全无用的连接,属于多余操作。 - 是否让方法接受已打开的连接:建议新增重载方法,允许传入已打开的连接。这样在执行多个关联查询(如同一事务下的操作)时,可复用同一个连接,避免多次从连接池取/还连接的开销,同时保证操作在同一上下文内执行。示例重载方法如下:
public virtual DataTable GetDataTable(SqlKata.Query query, DbConnection existingConn) { using (var Cmd = existingConn.CreateCommand()) { Cmd.CommandType = CommandType.Text; Cmd.CommandText = Compiler.Compile(query).ToString(); Cmd.Parameters.AddDummyParameter(); using (var DR = Cmd.ExecuteReader()) { DataTable DT = new DataTable(); DT.Load(DR); return DT; } } } - 是否让类复用单个连接对象:不建议这样做。长期持有单个连接会占用连接池资源,且若连接意外断开(如网络波动),后续所有操作都会失败。连接池的设计初衷就是让你按需创建、释放连接(实际是归还到池),以此高效管理连接资源。仅在需要连续执行多个关联操作(如事务)时,才应临时持有一个连接,操作完成后立即释放。
内容的提问来源于stack exchange,提问作者RFBomb
相关产品推荐
相关产品推荐

