假设我们有一个DAL方法
public void BuyProduct(int productId, int quantity, int buyerId);
在该方法中,我们需要调用2个存储过程:
创建2个SqlCommands是一个好习惯 - 每个存储过程一个并使用单个SqlConnection来执行这些命令吗?
OR
为每个SqlCommand创建单独的SqlConnection是否更好?
所以基本上我要问:在单个DAL方法中重复使用单个SqlConnection用于多个(2-4)SqlCommands是一个好习惯(显然在整个DAL中重用SqlConnection会很愚蠢)?
PS - 请不要问我为什么不能将2个存储过程合并为1.我的答案是 - 分离关注点。答案 0 :(得分:5)
真正的问题不是连接,而是交易。当逻辑操作涉及多个DAL物理操作时,通常它们必须是转换的一部分。除非corectness是可选的...如果一个事务跨越多个连接,那么它必须被提升到一个分布式事务,带来灾难性的perofrmance结果。因此,在设计DAL时,始终能够将事务关联到连接。这通过DAL API设计涟漪,因为通常结果是必须将连接和事务对象明确地分发给DAL方法,作为单独的参数或作为聚合它们的“上下文”对象。
答案 1 :(得分:2)
是的,将一个SqlConnection重用于多个SqlCommands(在一个方法中)是一个好习惯。据我所知,在你的情况下你还需要像这样使用SqlTransaction:
public void SomeDALMethod(string connectionString)
{
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var transaction = connection.BeginTransaction();
var command1 = new SqlCommand("tblOrders_CreateNewOrder", connection, transaction)
{
CommandType = CommandType.StoredProcedure
};
var command2 = new SqlCommand("tblProducts_RecalculateStock", connection, transaction)
{
CommandType = CommandType.StoredProcedure
};
try
{
command1.ExecuteNonQuery();
command2.ExecuteNonQuery();
transaction.Commit();
}
catch (Exception ex)
{
// Commit failed
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// Rollback failed
}
}
}
}
它允许您在第二次sp失败的情况下回滚第一个存储过程的执行。
答案 2 :(得分:1)
默认情况下,.NET会创建一个池化的SqlConnection。因此,创建新连接(前提是所有连接都使用相同的连接字符串)在池完全耗尽之前不会产生开销。
答案 3 :(得分:0)
此方法保持连接,只需在每次迭代时更改参数。只需提供正常的信息和一个返回参数列表的委托,基本上只是告诉它如何构建参数列表。类型T是您要从中构建参数列表的对象类型。仅当所有项目都失败时,它才返回false。
public static bool ExecuteBulkNonQuery<T>(string connectionString, CommandType commandType,
string commandText, IEnumerable<T> listItems, Func<T,SqlParameter[]> setParameters)
{
var fails = 0;
using (var conn = new SqlConnection(connectionString))
{
using (var comm = new SqlCommand(commandText, conn))
{
comm.CommandType = commandType;
conn.Open();
foreach (var obj in listItems)
{
comm.Parameters.Clear();
comm.Parameters.AddRange(setParameters.Invoke(obj));
fails += comm.ExecuteNonQuery();
}
return fails != 0;
}
}
}