我通常不鼓励在多个请求中共享一个 SqlConnection 实例。即使启用MARS,也可能会遇到性能问题。我认为当您的连接收到非读取命令时,连接缓冲区将暂停所有当前读取,直到写入完成。您真正节省的唯一一件事是建立连接所需的时间。
SqlConnections 是池化的,因此您可以将提供程序配置为具有可用于请求客户端的最小/最大实例数。请记住,这也由您连接到的任何数据库控制;假设您要连接到 SQL Server 实例,SQL Server 有自己的最大允许连接数设置。
我建议让您的公共成员接受命令字符串或命令参数,而不是允许客户端确定何时打开/关闭共享的 SqlConnection 实例。然后,类似于您的示例所建议的,从池中打开一个连接并执行该命令。
public IEnumerable<SqlResults> ExecuteStoredProcedure(string procedure, params SqlParameter[] parameters) {
using(SqlConnection connection = new SqlConnection(MyConnectionStringProperty)) {
try {
connection.Open();
using(SqlCommand command = new SqlCommand(procedure, connection)) {
command.CommandType = CommandType.StoredProcedure;
if(parameters != null) {
command.Parameters.AddRange(parameters);
}
// yield return to handle whatever results from proc execution
// can also consider expanding to support reader.NextResult()
using(SqlDataReader reader = command.ExecuteReader()) {
yield return new SqlResults {
Reader = reader;
};
}
}
}
finally {
if(connection.State != ConnectionState.Closed) {
connection.Close();
}
}
}
}
上面的示例代码就是这样——我在工作中使用的一个概念示例。该示例现在确实具有最大化的错误处理,但在返回和处理结果的方式上非常灵活。该类SqlResults
仅包含一个SqlDataReader
属性,并且可以扩展为包含错误。
只要static
您启用一种方法来制作提供者类的单例实例并且继续不共享任何可变属性(可能跨各种请求/线程),就可以进行任何操作。您可能需要考虑某种 IoC 或依赖注入方法来根据您的请求提供连接字符串。
编辑
Yield 允许调用者在执行上下文返回到产生返回以继续执行的方法之前使用返回的对象。因此,在上面的示例中,调用者可以执行以下操作:
// Since it's an IEnumerable we can handle multiple result sets
foreach(SqlResults results in MySqlHelper.ExecuteStoredProcedure(myProcedureName, new SqlParameter("myParamName", myParamValue)) {
// handle results
}
在我们处理结果时没有关闭连接。如果您在示例中注意到,我们有using
我们的SqlClient
对象的声明。这种方法允许将结果集处理与结果集处理分离,MySqlHelper
因为提供者类将处理可能重复的 SQL 提供代码,将结果处理委托给调用者,然后继续它必须做的事情(即关闭连接)。
至于 IoC/DI,我个人使用Castle Windsor。您可以将依赖对象作为属性或构造参数注入。将控制反转容器注册为依赖资源管理器将允许您(除其他外)在请求某种资源时返回相同的对象。基本上,对于每个需要使用的调用者类MySqlHelper
,您可以在调用者类被实例化或调用者类引用其公共MySqlHelper
属性时注入相同的实例。我个人更喜欢构造函数注入。另外,当我说注入时,我的意思是您不必担心设置属性值,因为您的 IoC/DI 会为您执行此操作(如果配置正确)。有关更深入的解释,请参见此处。
另外需要注意的是,IoC/DI 方法只有在您的类是非静态的时才会真正发挥作用,这样每个应用程序都可以拥有自己的单例实例。如果MySqlHelper
是静态的,那么除非您将其传入,否则您只能支持一个连接字符串,在您最初的问题中,您不希望这样做。IoC/DI 将允许您使用您的MySqlHelper
属性成员,就好像它是静态的一样,因为注册的容器将确保该属性具有正确的实例。