Isolation Level Serializable
如果對 transaction isolation 不太清楚可以先看 https://openhome.cc/Gossip/HibernateGossip/IsolationLevel.html
各種 Isolation Level 能解決的問題
Dirty Read |
Unrepeatable Read |
Phantom Read |
|
Read uncommitted | O | O | O |
Read committed | X | O | O |
Repreatable read | X | X | O |
Serializable | X | X | X |
Serializable
保證不會 DirtyRead => 讀到別的Transaction還沒Commit的資料
保證不會 Unrepeatable Read => 讀兩次有可能讀到不一樣的資料
保證不會 Phantom Read => 讀兩次有可能讀到不一樣的資料筆數
FirstTransaction 一樣讀取兩次,中間間隔10秒
SecondTransaction 會新增一筆資料
private static void Main(string[] args)
{
FirstTransaction();
//確保 FirstTransaction 跑完
Task.Delay(new TimeSpan(0, 0, 2)).Wait();
SecondTransaction();
Console.ReadKey();
}
private static async Task FirstTransaction()
{
using (var ts = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions()
// 設定 level
{ IsolationLevel = IsolationLevel.Serializable },
TransactionScopeAsyncFlowOption.Enabled))
{
using (var db = new StarGateDBEntities())
{
var list = await db.TableA.ToListAsync();
Console.WriteLine("-------First Read-------");
foreach (var item in list)
{
Console.WriteLine($"{ item.B }");
}
Console.WriteLine("-------First Read-------");
Console.WriteLine("Transaction 1 wait 10 seconds");
// 10 秒後再 讀一次
await Task.Delay(new TimeSpan(0, 0, 10));
list = await db.TableA.ToListAsync();
Console.WriteLine("-------Second Read-------");
foreach (var item in list)
{
Console.WriteLine($"{ item.B }");
}
Console.WriteLine("-------Second Read-------");
}
}
}
private static async Task SecondTransaction()
{
using (var ts = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions()
// 設定 level
{ IsolationLevel = IsolationLevel.ReadCommitted },
TransactionScopeAsyncFlowOption.Enabled))
{
using (var db = new StarGateDBEntities())
{
Console.WriteLine("Transaction 2 inserting");
db.TableA.Add(new TableA() { A = "A1", B = "add" });
await db.SaveChangesAsync();
ts.Complete();
Console.WriteLine("Transaction 2 saved!");
}
}
}
可以觀察到 SecondTransaction 的 insert 被卡住了
等到 FirstTransaction 第二次讀取後 insert 才成功
Serializable => 可以讀,要新增等我讀完再說
請注意 Repreatable read 只能擋住更新擋不住新增
請把 FirstTransaction 的 IsolationLevel 改成 RepeatableRead
可以觀察到 SecondTransaction 的 insert 是直接做完的
10秒後 FirstTransaction 第二次讀取就會多一筆資料了