悲观锁,乐观锁,行锁,表锁的所有区别与案例分析及个人总结

时间:2025-03-19 22:00:52

部分来源网址:
/puhaiyang/article/details/72284702

一,行锁:

    行锁的劣势:开销大;加锁慢;会出现死锁

    行锁的优势:锁的粒度小,发生锁冲突的概率低;处理并发的能力强

    加锁的方式:自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁;当然我们也可以显示的加锁:
    
    共享锁:select * from tableName where … + lock in share more

    排他锁:select * from tableName where … + for update


    行锁-->包含了悲观锁和乐观锁-->悲观所包含了

                             共享锁(只读:select * from tableName where … + lock in share more)和

                 排它锁(可读可写: select * from tableName where … + for update {nowait(直接抛出异常)/wait 3 (若等待后未结果直接抛出异常)/跳过 wait (直接读取其他未加锁的数据)}){悲观锁则适合解决并发竞争激烈的情况}

    行锁-->包含了悲观锁和乐观锁-->乐观锁(不加锁,解决并发 使用版本号+1或者时间戳来记录update/insert的最新数据)

    行锁中的乐观锁解决高并发方案:

    1.查询出商品信息

    select (status,status,version) from t_goods where id=#{id}

    2.根据商品信息生成订单

    3.修改商品status为2  update t_goods set status=2,version=version+1 where id=#{id} and version=#{version};

    乐观锁更适合解决冲突概率极小的情况;而悲观锁则适合解决并发竞争激烈的情况,尽量用行锁,缩小加锁粒度,以提高并发处理能力,即便加行锁的时间比加表锁的要长

二,总结脏读和不可重复读和幻读的场景以及解决方案(事务并发调度的问题):

    脏读(dirty read):A事务读取B事务尚未提交的更改数据,并在这个数据基础上操作。如果B事务回滚,那么A事务读到的数据根本不是合法的,称为脏读。在oracle中,由于有version控制,不会出现脏读。

    不可重复读(unrepeatable read):A事务读取了B事务已经提交的更改(或删除)数据。比如A事务第一次读取数据,然后B事务更改该数据并提交,A事务再次读取数据,两次读取的数据不一样。

    幻读(phantom read):A事务读取了B事务已经提交的新增数据。注意和不可重复读的区别,这里是新增,不可重复读是更改(或删除)。这两种情况对策是不一样的,对于不可重复读,只需要采取行级锁防止该记录数据被更改或删除,然而对于幻读必须加表级锁,防止在这个表中新增一条数据。

    脏读/不可重复读/幻读解决方案:

     脏读/不可重复读 使用行锁(悲观锁和乐观锁)解决,建议使用乐观锁,乐观锁更适合解决冲突概率极小的情况,而悲观锁则适合解决并发竞争激烈的情况。
     
    幻读 使用表锁解决,防止新增一条数据。

三,表锁和行锁应用场景:

    表级锁使用与并发性不高,以查询为主,少量更新的应用,比如小型的web应用;

    而行级锁适用于高并发环境下,对事务完整性要求较高的系统,如在线事务处理系统