第一次玩交易,我想我可以让下面的代码工作:
namespace database
{
class Program
{
static string connString = "Server=ServerName;Database=Demo;Trusted_Connection=True;";
SqlConnection connection = new SqlConnection(connString);
static Random r = new Random();
static void Add()
{
try
{
Thread.Sleep(r.Next(0, 10));
using (var trans = new TransactionScope())
{
using (var conn = new SqlConnection(connString))
{
conn.Open();
var count = (int)new SqlCommand("select balance from bank WITH (UPDLOCK) where owner like '%Jan%'", conn).ExecuteScalar();
Thread.Sleep(r.Next(0, 10));
SqlCommand cmd = new SqlCommand("update bank set balance = " + ++count + "where owner like '%Jan%'", conn);
cmd.ExecuteNonQuery();
}
trans.Complete();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static void Remove()
{
try
{
Thread.Sleep(r.Next(0, 10));
using (var trans = new TransactionScope())
{
using (var conn = new SqlConnection(connString))
{
conn.Open();
var count = (int)new SqlCommand("select balance from bank WITH (UPDLOCK) where owner like '%Jan%'", conn).ExecuteScalar();
Thread.Sleep(r.Next(0, 10));
SqlCommand cmd = new SqlCommand("update bank set balance = " + --count + "where owner like '%Jan%'", conn);
cmd.ExecuteNonQuery();
}
trans.Complete();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
Thread t = new Thread(new ThreadStart(Add));
t.Start();
}
for (int i = 0; i < 5; i++)
{
Thread t = new Thread(new ThreadStart(Remove));
t.Start();
}
Console.ReadLine();
}
}
}
我假设在 100 次加法和 100 次减法之后,我的 balane 将与我的起点相同 - 100,但是每次运行脚本时它都会上下变化。即使隔离级别可序列化。谁能告诉我为什么?o_o
编辑:将连接打开和关闭移动到事务范围内。现在的问题是我得到“事务(进程 ID XX)在锁定资源上与另一个进程死锁,并已被选为死锁受害者。重新运行事务”
就像 Marc Gravell 所说:将连接放在事务范围内并将 UPDLOCK 添加到选择查询中,并结合将隔离级别更改为可重复读取就可以了 :)
static void Add()
{
try
{
Thread.Sleep(r.Next(0, 10));
using (var trans = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = IsolationLevel.RepeatableRead }))
{
using (var conn = new SqlConnection(connString))
{
conn.Open();
var count = (int)new SqlCommand("select balance from bank WITH (UPDLOCK) where owner like '%Jan%'", conn).ExecuteScalar();
Thread.Sleep(r.Next(0, 10));
SqlCommand cmd = new SqlCommand("update bank set balance = " + ++count + "where owner like '%Jan%'", conn);
cmd.ExecuteNonQuery();
}
trans.Complete();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}