iT邦幫忙

0

交易 (處理序識別碼 91) 在 鎖定 | 通訊緩衝區 資源上被另一個處理序鎖死並已被選擇作為死結的犧牲者。請重新執行該交易。

  • 分享至 

  • xImage

我用C#寫了一支跟設備要資料的程式
並且每1分鐘會將資料寫入資料庫一次
(多個執行緒在寫入資料庫,下方程式碼是執行緒內在做的事情,我會一次開很多個執行緒做這些事情)
但常常寫一寫就會報Timeout的訊息
接著就出現標題那個死結的錯誤訊息
更奇怪的是
檢查錯誤訊息log檔發現
每天晚上12點-1點之間
會很頻繁的出現Timeout跟死結的錯誤訊息
其他時間則是偶發性的報錯
而報Timeout當下的那段SQL語法
直接拿去資料庫執行的話
基本上1秒內就跑完了
應該是不會Timeout才對
https://ithelp.ithome.com.tw/upload/images/20221109/20134563X8zOnobwJF.jpg

public void Running()
{
    while(true)
    {
        //Do Something...
        
        // 每分鐘回寫資料庫
        if (DateTime.Now.ToString("yyyy-MM-dd HH:mm") != strSQLRumTime)
        {
            strSQLRumTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm");

            if (!string.IsNullOrWhiteSpace(sbSQL.ToString()))
                ReadSQL(sbSQL.ToString());
        }
        
        Thread.Sleep(1000);
    }
}

public void ReadSQL(string pSQL)
{
    try
    {
        using (SqlConnection conn = new SqlConnection(conStr))
        {
            conn.Open();
            SqlCommand cmd = new SqlCommand(pSQL, conn);
            cmd.CommandTimeout = 10;
            cmd.ExecuteNonQuery();
            cmd.Cancel();
            conn.Close();
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
1
JamesDoge
iT邦高手 1 級 ‧ 2023-02-15 10:19:22
最佳解答

在 C# 中,你可以使用 TransactionScope 類來實現事務。

using (TransactionScope scope = new TransactionScope())
{
    try
    {
        // 執行第一個資料庫操作
        using (SqlConnection connection1 = new SqlConnection(connectionString1))
        {
            connection1.Open();

            // 在第一個連線上執行 SQL 指令
            SqlCommand command1 = new SqlCommand(commandText1, connection1);
            command1.ExecuteNonQuery();
        }

        // 執行第二個資料庫操作
        using (SqlConnection connection2 = new SqlConnection(connectionString2))
        {
            connection2.Open();

            // 在第二個連線上執行 SQL 指令
            SqlCommand command2 = new SqlCommand(commandText2, connection2);
            command2.ExecuteNonQuery();
        }

        // 如果成功完成以上的所有資料庫操作,則提交交易
        scope.Complete();
    }
    catch (Exception ex)
    {
        // 如果有任何例外情況發生,交易將被回滾
        Console.WriteLine("Error: " + ex.Message);
    }
}

這個範例建立了一個 TransactionScope 物件,包含兩個資料庫操作。這兩個操作會被視為一個交易

皓皓 iT邦新手 3 級 ‧ 2023-02-17 10:43:05 檢舉

原來還有這種用法!

0
ilwu
iT邦新手 5 級 ‧ 2022-11-09 10:43:38

12點-1點 很容易碰到其他排程在跑 (不知道為什麼大家很愛用這個時間 XD)
也許不是你這段程式的問題,是同一時間有一個大的程序正在跑
並且拉了 trancation
在此時你的 sql 就會被 這個 trancation 擋住,並且等待
如果對方執行超過 10 秒的話 (上方程式設 10 秒)
你寫檔的程式就直接放棄 time out 了

建議可以改個時間,或是拉長 timeout 時間試試看

皓皓 iT邦新手 3 級 ‧ 2022-11-09 10:50:01 檢舉

同一時間有一個大的程序正在跑

關於這個想請問一下,就算其他程序insert或update的表是不同的,也一樣會被擋住並卡在那邊嗎?

建議可以改個時間,或是拉長 timeout 時間試試看

改個時間是指我寫入資料庫的時間點嗎?但因為我是固定每分鐘寫入,不管怎麼樣好像都會卡到,所以好像只能拉長timeout時間了

ilwu iT邦新手 5 級 ‧ 2022-11-09 11:04:00 檢舉

關於這個想請問一下,就算其他程序insert或update的表是不同的,也一樣會被擋住並卡在那邊嗎?

這個不會

改個時間是指我寫入資料庫的時間點嗎?但因為我是固定每分鐘寫入,不管怎麼樣好像都會卡到,所以好像只能拉長timeout時間了

如果有把握 SQL 其實跑很快的話, timeout 時間設定長也沒關係
因為不會用到上限 (上方程式直接砍10秒設定那行的話,是預設30秒)

不過記得,如果你的程式的動作是
read -> process -> write result
記得要用 trancation 包起來

因為有被 lock 就代表有其他程式正在異動同樣的 table
不包的話, read 會少掉其他程式異動的結果
計算出來之後,回寫的結果也會不對 (dirty read)

另外還有一個思路,
去找 SQL server 上的 log , 看看 12-01 之間有哪些sql在執行
然後去探討這個程序為何需要把你用到的 table 也包進 trancation

其實如果這個 table 不是很重要的交易資料檔的話
或許可以請對方將『讀取』資料的部分,放到 trancation 外面

皓皓 iT邦新手 3 級 ‧ 2022-11-09 15:46:36 檢舉

了解,感謝解答~
我應該有些概念了,大概知道可以怎麼處理了

0
alien663
iT邦研究生 5 級 ‧ 2022-11-09 10:57:22
皓皓 iT邦新手 3 級 ‧ 2022-11-09 15:47:35 檢舉

謝謝大大~

我要發表回答

立即登入回答