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

本文探讨了MySQL中forupdate和lockinsharemode两种锁机制的区别及其应用场景。通过对比这两种锁的效果和测试代码,揭示了如何使用它们来防止并发情况下出现的幻读现象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


 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();

        }


上面的情况会出现幻读




<think>嗯,用户想知道如何在MySQL中实现不同类型的锁机制及其实现方法。首先,我需要回顾一下MySQL的锁机制,包括锁的类型使用方法。根据之前的引用资料,MySQL主要有共享锁(S锁)排他锁(X锁),还有行级锁表级锁的区别。用户可能还关心如何显式地使用这些锁,比如通过SQL语句。 首先,我应该分清楚锁的类别。表级锁行级锁是不同的,表级锁会影响整个表,而行级锁只影响特定行。共享锁排他锁属于这两种级别的锁。共享锁允许其他事务读但不可,而排他锁则阻止其他事务的读。比如,SELECT ... LOCK IN SHARE MODE会加共享锁,而SELECT ... FOR UPDATE会加排他锁。 然后,用户可能需要知道如何在实际操作中使用这些锁。例如,在事务中显式地加锁,或者通过设置隔离级别来隐式控制锁。另外,死锁的问题也很重要,需要提到如何检测处理死锁,以及优化建议,比如减少事务时间、按顺序访问资源等。 还有,用户提到的分布式锁可能涉及到使用MySQLFOR UPDATE来实现,这也是需要解释的部分。不过,重点应该放在MySQL本身的锁机制,而不是其他系统如Redis或Zookeeper的实现。 我需要确保回答结构清晰,分点说明不同类型的锁及其实现方法,并给出示例代码。同时,根据引用资料,要注意自动死锁检测手动处理的情况,以及锁优化的建议,比如索引的使用事务设计。 可能还需要检查是否有遗漏的锁类型,比如意向锁,但根据引用资料,主要讨论的是共享锁、排他锁、表锁行锁。另外,注意在示例中使用正确的SQL语法,比如在事务中使用BEGIN或START TRANSACTION,然后执行加锁的查询,最后COMMIT。 最后,生成的相关问题需要围绕MySQL锁的进阶内容,比如隔离级别的影响、死锁处理、性能优化分布式锁的实现,确保问题有针对性,帮助用户进一步学习。</think>### MySQL锁机制实现方法分步说明 #### 一、MySQL锁类型及实现方式 1. **共享锁(S锁)** 允许读取操作并行,阻止入操作 ```sql SELECT * FROM table_name WHERE id = 1 LOCK IN SHARE MODE; ``` 此时其他事务仍可获取共享锁,但无法获取排他锁[^2] 2. **排他锁(X锁)** 独占资源,禁止其他事务读 ```sql SELECT * FROM table_name WHERE id = 1 FOR UPDATE; ``` 常用于更新操作前锁定数据 3. **表级锁实现** ```sql LOCK TABLES table_name READ; -- 共享表锁 LOCK TABLES table_name WRITE; -- 排他表锁 UNLOCK TABLES; ``` 注意:MyISAM引擎默认使用表级锁[^1] 4. **行级锁实现** InnoDB引擎特有,自动在索引记录上加锁: ```sql -- 自动行锁示例 START TRANSACTION; UPDATE products SET stock = stock-1 WHERE product_id = 100; COMMIT; ``` #### 二、锁机制实践要点 1. **事务隔离级别影响** REPEATABLE READ级别下会使用间隙锁防止幻读 READ COMMITTED级别使用更宽松的锁定策略[^3] 2. **死锁处理** ```sql SHOW ENGINE INNODB STATUS; -- 查看最近死锁信息 ``` MySQL自动检测死锁后会回滚较小的事务 3. **锁优化建议** - 为查询条件字段建立索引 - 控制事务粒度 - 避免长事务 - 统一资源访问顺序[^3] #### 三、分布式锁实现 通过FOR UPDATE实现基本分布式锁: ```sql START TRANSACTION; SELECT * FROM lock_table WHERE resource_name='order_123' FOR UPDATE; -- 执行业务逻辑 COMMIT; ``` 该方法需配合唯一约束字段使用[^4] $$锁冲突矩阵 = \begin{cases} S锁 & 兼容S锁,排斥X锁 \\ X锁 & 排斥所有锁 \\ \end{cases}$$[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值