You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SSIS脚本任务锁机制引发变量死锁,无法发送SQL查询结果邮件

SSIS脚本任务变量死锁问题修复方案

错误原因分析

出现变量死锁超时的核心问题在于变量锁使用不规范,加上资源未正确释放:

  • 已通过VariableDispenser锁定变量,却同时使用Dts.Variables直接访问,引发锁冲突
  • 变量解锁操作vars.Unlock()位置不合理,未覆盖所有执行路径(如异常、提前返回)
  • 错误使用SqlConnection连接DB2数据库,可能导致连接泄漏,间接影响锁资源释放
  • 未在finally块中统一处理资源释放,异常场景下锁和连接无法正常释放

修复后的完整代码

public void Main()
{
    Variables vars = null;
    // 使用DB2专属连接类
    IBM.Data.DB2.DB2Connection conn = null;
    int insertedRows1 = 0;
    int insertedRows2 = 0;
    int updatedRows11 = 0;
    int updatedRows12 = 0;
    int updatedRows21 = 0;
    int updatedRows22 = 0;
    int deletedRows = 0;
    string ServerName = string.Empty;

    try
    {
        // 一次性锁定所有需要的变量
        Dts.VariableDispenser.LockForRead("User::isDataFlowSuccessful");
        Dts.VariableDispenser.LockForRead("$Package::Environment");
        Dts.VariableDispenser.LockForRead("$Package::SqlDatabaseServer");
        Dts.VariableDispenser.LockForRead("User::InsertedRowCount1");
        Dts.VariableDispenser.LockForRead("User::UpdatedRowCount11");
        Dts.VariableDispenser.LockForRead("User::UpdatedRowCount12");
        Dts.VariableDispenser.LockForRead("User::InsertedRowCount2");
        Dts.VariableDispenser.LockForRead("User::UpdatedRowCount21");
        Dts.VariableDispenser.LockForRead("User::UpdatedRowCount22");
        Dts.VariableDispenser.LockForRead("User::DeletedRowCount");
        Dts.VariableDispenser.LockForWrite("User::emailsubject");
        Dts.VariableDispenser.LockForWrite("User::emailbody");

        Dts.VariableDispenser.GetVariables(ref vars);

        // 统一通过vars对象读写变量
        insertedRows1 = (int)vars["User::InsertedRowCount1"].Value;
        insertedRows2 = (int)vars["User::InsertedRowCount2"].Value;
        updatedRows11 = (int)vars["User::UpdatedRowCount11"].Value;
        updatedRows12 = (int)vars["User::UpdatedRowCount12"].Value;
        updatedRows21 = (int)vars["User::UpdatedRowCount21"].Value;
        updatedRows22 = (int)vars["User::UpdatedRowCount22"].Value;
        deletedRows = (int)vars["User::DeletedRowCount"].Value;
        ServerName = (string)vars["$Package::SqlDatabaseServer"].Value;
        bool isDataFlowSuccessful = (bool)vars["User::isDataFlowSuccessful"].Value;
        string Environment = (string)vars["$Package::Environment"].Value;

        int totalInsertedRows = insertedRows1 + insertedRows2;
        int totalUpdatedRows = updatedRows11 + updatedRows12 + updatedRows21 + updatedRows22;
        string message = string.Empty;
        string sql = "SELECT FISCAL_YR, LOC_CODE, COUNT(*) FROM LC1U1.Location_Supertbl1 GROUP BY FISCAL_YR, LOC_CODE;";

        string connString = Dts.Connections["TDB1 Connection Manager"].ConnectionString;
        conn = new IBM.Data.DB2.DB2Connection(connString);
        StringBuilder resultBuilder = new StringBuilder();

        conn.Open();
        using (IBM.Data.DB2.DB2Command cmd = new IBM.Data.DB2.DB2Command(sql, conn))
        {
            using (IBM.Data.DB2.DB2DataReader reader = cmd.ExecuteReader())
            {
                // 正确读取多列查询结果
                while (reader.Read())
                {
                    resultBuilder.AppendLine($"财政年度: {reader["FISCAL_YR"]}, 位置代码: {reader["LOC_CODE"]}, 数量: {reader[2]}");
                }
            }
        }

        message = resultBuilder.ToString();

        if (isDataFlowSuccessful)
        {
            vars["User::emailsubject"].Value = $"LCGMS_Supertable_Update_Process_LC1P1_{Environment}:{ServerName} Success on {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
            vars["User::emailbody"].Value = $"总计插入 {totalInsertedRows} 行, 更新 {totalUpdatedRows} 行, 删除 {deletedRows} 行\n\n{message}\nEND";
            Dts.TaskResult = (int)ScriptResults.Success;
        }
        else
        {
            vars["User::emailsubject"].Value = $"LCGMS_Supertable_Update_Process_LC1P1_{Environment}:{ServerName} Failure on {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
            vars["User::emailbody"].Value = $"总计插入 {totalInsertedRows} 行, 更新 {totalUpdatedRows} 行, 删除 {deletedRows} 行\n\n{message}\nEND";
            Dts.TaskResult = (int)ScriptResults.Failure;
        }
    }
    catch (Exception ex)
    {
        Dts.Events.FireError(0, "Script Task Error", $"{ex.Message}\n{ex.StackTrace}", string.Empty, 0);
        Dts.TaskResult = (int)ScriptResults.Failure;
    }
    finally
    {
        // 确保所有场景下释放变量锁
        if (vars != null)
        {
            vars.Unlock();
        }
        // 确保DB连接被关闭释放
        if (conn != null && conn.State != System.Data.ConnectionState.Closed)
        {
            conn.Close();
            conn.Dispose();
        }
        // 释放连接管理器资源
        Dts.Connections["TDB1 Connection Manager"].ReleaseConnection(null);
    }
}

enum ScriptResults
{
    Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
    Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};

关键修复点

  • 统一变量访问:通过VariableDispenser获取vars对象后,所有变量操作均通过该对象完成,避免锁冲突
  • 强制资源释放:将变量解锁、DB连接关闭逻辑放在finally块,覆盖所有执行路径
  • 适配DB2连接:替换为IBM官方DB2驱动类,避免连接类型不匹配问题
  • 优化数据读取:修正原代码只读取第一列的错误,正确拼接多列查询结果
  • 简化代码逻辑:移除冗余判断,使用字符串插值提升可读性

内容的提问来源于stack exchange,提问作者Steven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 15:54:52