我用C#寫了一支跟設備要資料的程式
並且每1分鐘會將資料寫入資料庫一次
(多個執行緒在寫入資料庫,下方程式碼是執行緒內在做的事情,我會一次開很多個執行緒做這些事情)
但常常寫一寫就會報Timeout的訊息
接著就出現標題那個死結的錯誤訊息
更奇怪的是
檢查錯誤訊息log檔發現
每天晚上12點-1點之間
會很頻繁的出現Timeout跟死結的錯誤訊息
其他時間則是偶發性的報錯
而報Timeout當下的那段SQL語法
直接拿去資料庫執行的話
基本上1秒內就跑完了
應該是不會Timeout才對
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;
}
}
在 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 物件,包含兩個資料庫操作。這兩個操作會被視為一個交易
12點-1點 很容易碰到其他排程在跑 (不知道為什麼大家很愛用這個時間 XD)
也許不是你這段程式的問題,是同一時間有一個大的程序正在跑
並且拉了 trancation
在此時你的 sql 就會被 這個 trancation 擋住,並且等待
如果對方執行超過 10 秒的話 (上方程式設 10 秒)
你寫檔的程式就直接放棄 time out 了
建議可以改個時間,或是拉長 timeout 時間試試看
同一時間有一個大的程序正在跑
關於這個想請問一下,就算其他程序insert或update的表是不同的,也一樣會被擋住並卡在那邊嗎?
建議可以改個時間,或是拉長 timeout 時間試試看
改個時間是指我寫入資料庫的時間點嗎?但因為我是固定每分鐘寫入,不管怎麼樣好像都會卡到,所以好像只能拉長timeout時間了
關於這個想請問一下,就算其他程序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 外面
了解,感謝解答~
我應該有些概念了,大概知道可以怎麼處理了
這邊推薦幾個網站學習一下deadlock的知識,算是資料庫操作中比較細節的部分
What are SQL Server deadlocks and how to monitor them