我有以下使用SqlTransaction
的代码string connectionString = ConfigurationManager.AppSettings["ConnectionString"];
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
int logID = HelperClass.InsertException(connection, 1, DateTime.Now, "Y", "test", "test", 1, 1, transaction);
LogSearch logSearch = new LogSearch();
logSearch.LogID = 258;
Collection<Log> logs = HelperClass.GetLogs(logSearch, connectionString);
}
此代码抛出以下异常。
超时已过期。操作完成之前经过的超时时间或服务器没有响应。
但是,如果我为LogID传递硬编码值,则没有例外。
问题
hard coded
值作为LogID 注意:InsertException()使用与SqlTransaction
的连接,而GetLogs()使用没有任何事务的新连接
更新的问题
业务层代码不使用Transaction
。我需要在上面显示的单元测试代码中调用业务层方法(用于集成测试)。即使业务层不使用事务,我们如何将事务应用于UT代码(用于集成测试)?从@jbl回答看来,似乎完全不可能在单元测试中使用事务。我们如何为UT代码申请交易。
CODE
public static class HelperClass
{
public static Collection<Log> GetLogs(LogSearch logSearch, string connectionString)
{
Collection<Log> logs = new Collection<Log>();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string commandText = "SELECT * FROM Application_EX WHERE application_ex_id = @application_ex_id";
using (SqlCommand command = new SqlCommand(commandText, connection))
{
command.CommandType = System.Data.CommandType.Text;
//Parameter value setting
command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
}
}
}
}
}
return logs;
}
public static Int16 InsertException(SqlConnection connection, Int16 applicationID, DateTime createdDate, string isInternalLocationIndicator, string exceptionDescription, string operation, Int16 severityLevelNumber, Int16 exceptionTypeCode, SqlTransaction transaction)
{
Int16 newLogID = 0;
string commandText = @"INSERT INTO Application_Ex
VALUES (@severity_level_nbr, @appl_service_id, @ex_internal_appl_ind,
@application_ex_txt,@ex_location_txt,@create_ts,@application_ex_code);
SELECT SCOPE_IDENTITY() AS [LogIdentity];";
using (SqlCommand command = new SqlCommand(commandText, connection, transaction))
{
command.CommandType = System.Data.CommandType.Text;
command.Parameters.AddWithValue("@severity_level_nbr", severityLevelNumber);
command.Parameters.AddWithValue("@appl_service_id", applicationID);
command.Parameters.AddWithValue("@ex_internal_appl_ind", isInternalLocationIndicator);
command.Parameters.AddWithValue("@application_ex_txt", exceptionDescription);
command.Parameters.AddWithValue("@ex_location_txt", operation);
command.Parameters.AddWithValue("@create_ts", createdDate);
command.Parameters.AddWithValue("@application_ex_code", exceptionTypeCode);
newLogID = Convert.ToInt16(command.ExecuteScalar(), CultureInfo.InvariantCulture);
}
return newLogID;
}
}
答案 0 :(得分:7)
问题
答复
假设你的方法GetLogs正在另一列上搜索表,一个非pk列(例如application_message),那么必须读取整个表以找到一行(或多行),其中包含application_message的相应值。这将导致查询始终触及新插入的锁定行,然后还会使用硬编码(application_message)值获得超时异常。我添加的只是为了澄清锁定,当SQL确实或不需要触摸锁定的行时。
希望这有帮助。
答案 1 :(得分:4)
我想那是因为HelperClass.GetLogs(logSearch, connectionString);
在您的交易范围之外实例化了一个新连接:
您可以随意:
"SELECT * FROM Application_EX WHERE application_ex_id = @application_ex_id"
替换为"SELECT * FROM Application_EX with (nolock) WHERE application_ex_id = @application_ex_id"
请注意,第二种情况有时会返回不正确的值,并且不会返回您当前在事务中插入的值
希望这会有所帮助