将事务结果用作参数时发生超时错误

LCJ*_*LCJ 1 c# concurrency ado.net transactions

我有以下使用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);
}
Run Code Online (Sandbox Code Playgroud)

此代码抛出以下异常.

超时已过期.操作完成之前经过的超时时间或服务器没有响应.

但是,如果我为LogID传递硬编码值,则没有例外.

  1. 当我传递logID(来自InsertException()的结果)时,为什么会出现异常?
  2. 请解释为什么我将hard coded值传递为LogID 时没有异常

注意:InsertException()使用连接,SqlTransaction而GetLogs()使用没有任何事务的新连接

更新的问题

业务层代码不使用Transaction.我需要在上面显示的单元测试代码中调用业务层方法(用于集成测试).即使业务层不使用事务,我们如何将事务应用于UT代码(用于集成测试)?从@jbl回答看来,似乎完全不可能在单元测试中使用事务.我们如何应用UT代码的交易.

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;

    }
}
Run Code Online (Sandbox Code Playgroud)

Maa*_*ten 7

  1. 当我传递logID(来自InsertException()的结果)时,为什么会出现异常?
  2. 请解释为什么我将硬编码值作为LogID传递时没有异常

解答

  1. 使用事务插入新记录时,这意味着在您自己提交事务之前,最终不会提交新记录.在那之前,新记录是LOCKED,这意味着任何触及该新记录的查询都将暂停,直到发生超时.在您的情况下,在事务仍在运行时执行对GetLogs方法的调用,并且该方法搜索新插入的记录ID.由于该行被锁定,您的GetLogs调用将等待超时发生,这将导致超时异常.
  2. 在硬编码值的情况下,对GetLogs的调用将搜索具有相应id的现有记录.由于您正在搜索PK值,因此SQL不必搜索所有行,因为它是PK.因此,在单独的事务中找到并返回现有行,因为事务在它们触摸的数据中不重叠.

假设您的方法GetLogs正在另一列(非pk列(例如application_message))上搜索表,则必须读取整个表以查找具有application_message的相应值的行(或行).这将导致查询始终触及新插入的锁定行,然后还会使用硬编码(application_message)值获得超时异常.我添加的只是为了澄清锁定,当SQL确实或不需要触摸锁定的行时.

希望这可以帮助.

  • 您可以尝试使用TransactionScope围绕测试代码,http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx.这将以环境方式在同一事务中运行您的连接.不确定它是否会起作用,因为当您使用第二个查询调用方法时,第一个查询的连接仍在代码中打开.值得一试. (2认同)