一、锁的兼容性

    InnoDB 实现了以下两种类型的行锁
        共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁
        排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁
    为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB 还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁
        意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的 IS 锁
        意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的 IX 锁


    在mysql中有表锁
        LOCK TABLE my_tabl_name READ 用读锁锁表,会阻塞其他事务修改表数据
        LOCK TABLE my_table_name WRITe 用写锁锁表,会阻塞其他事务读和写


    Innodb引擎又支持行锁,行锁分为
        共享锁,一个事务对一行的共享只读锁
        排它锁,一个事务对一行的排他读写锁


    这两中类型的锁共存的问题
        1)事务A锁住了表中的一行,让这一行只能读,不能写
        2)之后,事务B申请整个表的写锁
        如果事务B申请成功,那么理论上它就能修改表中的任意一行,这与A持有的行锁是冲突的
        数据库需要避免这种冲突,就是说要让B的申请被阻塞,直到A释放了行锁
        数据库要怎么判断这个冲突呢?
        step1:判断表是否已被其他事务用表锁锁表
        step2:判断表中的每一行是否已被行锁锁住
        注意step2,这样的判断方法效率实在不高,因为需要遍历整个表
        于是就有了意向锁
        在意向锁存在的情况下,事务A必须先申请表的意向共享锁,成功后再申请一行的行锁
        在意向锁存在的情况下,上面的判断可以改成
        step1:不变
        step2:发现表上有意向共享锁,说明表中有些行被共享行锁锁住了,因此,事务B申请表的写锁会被阻塞
        注意:申请意向锁的动作是数据库完成的,就是说,事务A申请一行的行锁的时候,数据库会自动先开始申请表的意向锁,不需要我们程序员使用代码来申请

二、锁的实现方式

InnoDB加锁方法
        意向锁是 InnoDB 自动加的, 不需用户干预
        对于 UPDATE、 DELETE 和 INSERT 语句, InnoDB会自动给涉及数据集加排他锁(X)
        对于普通 SELECT 语句,InnoDB 不会加任何锁
        事务可以通过以下语句显式给记录集加共享锁或排他锁
            共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。 其他 session 仍然可以查询记录,并也可以对该记录加 share mode 的共享锁。但是如果当前事务需要对该记录进行更新操作,则很有可能造成死锁
            排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE。其他 session 可以查询该记录,但是不能对该记录加共享锁或排他锁,而是等待获得锁

显式锁定 
        select ... lock in share mode //共享锁 
        select ... for update //排他锁 


select for update

        在执行这个 select 查询语句的时候,会将对应的索引访问条目进行上排他锁(X 锁),也就是说这个语句对应的锁就相当于update带来的效果。

        使用场景:为了让自己查到的数据确保是最新数据,并且查到后的数据只允许自己来修改的时候,需要用到 for update 子句。

select lock in share mode

        in share mode 子句的作用就是将查找到的数据加上一个 share 锁,这个就是表示其他的事务只能对这些数据进行简单的select 操作,并不能够进行 DML 操作

        使用场景:为了确保自己查到的数据没有被其他的事务正在修改,也就是说确保查到的数据是最新的数据,并且不允许其他人来修改数据。但是自己不一定能够修改数据,因为有可能其他的事务也对这些数据 使用了 in share mode 的方式上了 S 锁。

性能影响
        select for update 语句,相当于一个 update 语句。在业务繁忙的情况下,如果事务没有及时的commit或者rollback 可能会造成其他事务长时间的等待,从而影响数据库的并发使用效率
        select lock in share mode 语句是一个给查找的数据上一个共享锁(S 锁)的功能,它允许其他的事务也对该数据上S锁,但是不能够允许对该数据进行修改。如果不及时的commit 或者rollback 也可能会造成大量的事务等待

 

乐观锁、悲观锁

        悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

        乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。

        两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。


死锁

        死锁一般是事务相互等待对方资源,最后形成环路造成的。
        对于死锁,数据库处理方法:牺牲一个连接,保证另外一个连接成功执行。
        发生死锁会返回ERROR:1213 错误提示,大部分的死锁InnoDB存储引擎本身可以侦测到,不需要人为进行干预。
        注意:InnoDB存储引擎并不会回滚大部分的错误异常,像阻塞章节里面的例子,但是死锁例外,发现死锁后,InnoDB存储引擎会马上回滚一个事务,会返回1213错误。

两个事务中同时修改一条数据都未回滚或者提交,相互等待

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值