http://www.cnblogs.com/zhenyulu/articles/330494.html
参考了上面这片对并发控制处理的文章,有些迷茫,自己做了实验,如下:
private static string connstr = "Server=(local);Database=DBApp;Trusted_Connection=True;";
SqlConnection conn;
SqlConnection conn2;
SqlTransaction tran;
SqlTransaction tran2;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Setup();
//读取数据
SqlCommand cmd = conn.CreateCommand();
cmd.Connection = conn;
cmd.CommandText = "select * from SC where ID=1 and cno=1";
cmd.Transaction = tran;
try
{
SqlDataReader dr=cmd.ExecuteReader();
while (dr.Read())
{
textBox1.Text = dr[0].ToString();
textBox2.Text = dr[1].ToString();
textBox3.Text = dr[2].ToString();
}
dr.Close();
}
catch (Exception ee)
{
MessageBox.Show(ee.Message);
tran.Rollback();
}
}
private void button1_Click(object sender, EventArgs e)
{
Setup();
//保存数据
SqlCommand cmd = conn2.CreateCommand();
cmd.Connection = conn2;
cmd.CommandText = "update SC set mark="+Convert.ToDouble(textBox3.Text.ToString())+" where ID=1 and cno=1";
cmd.Transaction = tran2;
try
{
cmd.ExecuteScalar();
tran2.Commit();
tran.Commit();
}
catch (Exception ee)
{
MessageBox.Show(ee.Message);
tran2.Rollback();
}
finally
{
conn.Close();
conn2.Close();
}
}
private void Setup()
{
conn = new SqlConnection(connstr);
conn.Open();
conn2=new SqlConnection(connstr);
conn2.Open();
tran = conn.BeginTransaction(IsolationLevel.RepeatableRead);
tran2 = conn2.BeginTransaction(IsolationLevel.RepeatableRead);
}
private void button2_Click(object sender, EventArgs e)
{
Close();
}
同时开两个窗口,依次在两个窗口内对数据库进行操作,RepeatableRead模式下,保存操作都失败,究其原由是在三封锁对应RepeatableRead模式,该模式对数据读加了S锁(共享锁),并且要到事务结束才会释放,第一个事务在需要update的时候,必须给数据加x锁(写锁),因为此时第二个窗口的事务尚未结束,也就是说s锁还加在这个处理之上,在s锁未失效的情况下,其他事务只能对该数据对象加s锁而不能加x锁,从而造成了事务一也就是窗口一在更新的时候出现死锁,等待窗口二事务的解锁。超时后,事务一处理回滚,更新不成功。
这种方式,虽然能避免并发,但是处理方式不能友好,觉得还是可以用Scott Mitchell在ASP.NET2.0数据指南中的方法,在where字句中处理并发问题。关于效率问题,以后有时间再做测试。
以上两个事务,在同时改为ReadCommitted的模式下,在并发时,测试失败,两个窗口都可以更新数据。