mysql 并行写 for update lock in share mode 总结

来源:互联网 发布:cnc编程学徒工资待遇 编辑:程序博客网 时间:2024/05/08 23:44


 mysql 默认事务级别会出现幻读的可能性,两个事务同时执行,第一个事务写入一条数据;第二个事务查询不到, 如果是串行访问不会有什么问题;我们一个项目是多个客户端向服务器并行写入相同的数据,系统架构改造成本大,所以在服务器事务中加了锁,避免出现这种情况


 加锁有两个办法,分别是 for update, lock in share mode


for update 是IX锁(意向排它锁),即在符合条件的rows上都加了排它锁,其他session也就无法在这些记录上添加任何的S锁或X锁。如果不存在一致性非锁定读的话,那么其他session是无法读取和修改这些记录的,但是innodb有非锁定读(快照读并不需要加锁),for update之后并不会阻塞其他session的快照读取操作,除了select ...lock in share mode和select ... for update这种显示加锁的查询操作。


  lock in share mode :是IS锁(意向共享锁),即在符合条件的rows上都加了共享锁,这样的话,其他session可以读取这些记录,也可以继续添加IS锁,但是无法修改这些记录直到你这个加锁的session执行完成(否则直接锁等待超时)。 


 总结:经过测试, 这两种模式加锁的表无数据的情况下,锁不会起作用,必须加锁的表必须有数据。 lock in share mode 也叫间隙锁,带where 条件加锁,where字段是整型并且是主键,会变成行锁。

lock in share mode: 如果多个事务,都获取了这个锁;第一个事务向此表插入数据,会等待其它事务释放此锁;此时如果第二个事务也做插入,第二个事务会直接报Deadlock found when trying to get lock; try restarting transaction异常,第一个事务正常往下执行。此种情况要用 for update 。 如果锁住的是A表,插入或者修改的是B表,B表仍然会出现幻读。

for update, 要求表有数据,此时锁住的是A表,对B表的插入与更新也不会导致幻读。


测试代码1

  public void querylock()        {            DataTable dt = null;            db.BeginTransaction();            string sql = "  select * from company  lock in share mode  ";  // select * from yyb_chkshopresult where session_id='261'  for update            db.ExecuteNonQuery(sql);            sql = " insert into e_location values('1','a1')";            db.ExecuteNonQuery(sql);            System.Threading.Thread.Sleep(5000);            sql = " select * from e_location ";            dt = db.ExecuteDataTableT(sql);            //sql = " select count(*) from yyb_chkshopresult where session_id='26' ";            //db.ExecuteScalarString(sql);            db.Commit();            string dtime = DateTime.Now.ToString();        }



测试代码2

public void querylock()        {            DataTable dt = null;            db.BeginTransaction();            string sql = " select * from company  lock in share mode   ";            db.ExecuteNonQuery(sql);            sql = " select * from e_location where locationcode='1' ";            dt = db.ExecuteDataTableT(sql);            if (dt.Rows.Count==0)            {                sql = " insert into e_location values('2','a2')";                db.ExecuteNonQuery(sql);            }            sql = " select * from e_location ";            dt = db.ExecuteDataTableT(sql);            db.Commit();            string dtime = DateTime.Now.ToString();        }


上面的情况会出现幻读




0 0