我是少侠露飞。博客不仅是笔记,更是一种思考,一种分享。
MySQL的锁机制是面试中的难点,也是时常让开发头疼的问题,今天少侠就做个总结。
注意,无论是共享锁还是排它锁都是行锁。
在Java中常见的采用CAS算法实现的乐观锁的典型的例子就是原子类,通过CAS自旋实现原子操作的更新,悲观锁通常都是synchronized和Lock实现。那么MySQL中的乐观锁和悲观锁又为何呢?
乐观锁:每次读数据的时候都认为其他人不会修改,所以不会上锁,而是在更新的时候去判断在此期间有没有其他人更新了数据,可以使用版本号机制。在数据库中可以通过为数据表增加一个版本号字段实现。读取数据时将版本号一同读出,数据每次更新时对版本号加一。当我们更新的时候,判断数据库表对应记录的当前版本号与第一次取出来的版本号值进行比对,如果值相等,则予以更新,否则认为是过期数据。乐观锁适用于多读的应用类型,可以提高吞吐量。 # 利用版本号进行CAS更新 UPDATE table t SET t.name='Luffy' WHERE t.id = 1 AND version = 678768; 悲观锁:每次读数据的时候都认为别人会修改,所以每次在读数据的时候都会上锁,这样别人想读这个数据时就会被阻塞。MySQL中就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在操作之前先上锁。上节的S锁(共享锁)和X锁(排它锁)都是悲观锁。
InnoDB有三种行锁的算法:
Record Lock:单个记录上的锁。Gap Lock:间隙锁,锁定一个索引范围,但不包含记录本身。Next-Key Lock:Gap Lock + Record Lock,锁定一个索引范围,并且包含记录本身。间隙锁使得InnoDB解决幻读问题,加上MVCC使得InnoDB的RR隔离级别实现了串行化级别的效果,并且保留了比较好的并发性能。
定义:当我们用范围条件检索数据时请求共享或排他锁时,InnoDB会给符合条件的已有数据的索引加锁;对于键值在条件范围内但表中并不存在的记录,叫做间隙(GAP),InnoDB也会对这个"间隙"加锁,这种锁机制就是间隙锁。 例如:table表中存在id 1-80,90-99的记录。SELECT * FROM table WHERE id < 100 FOR UPDATE。InnoDB不仅会对id值为1-80,90-99的记录加锁,也会对id在81-89之间(这些记录并不存在)的间隙加锁。这样就能避免事务隔离级别为可重复读下的幻读。
概念:两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。 存在条件:1、 互斥条件:一个资源每次只能被一个事务使用。2、 请求与保持条件:一个事务因请求资源而阻塞时,对已获得的资源保持不放。3、不剥夺条件:已获得的资源,在末使用完之前不能强行剥夺。4、循环等待条件:形成一种头尾相接的循环等待关系。 解除正在死锁的状态:撤销其中一个事务。
手写一段死锁代码:
T1: begin; select * from user u where u.id=1 for update; update user u set u.name='Carson' where id=2; T2: begin; delete from user u where u.id=2; delete from user u where u.id=1;本篇重点介绍了MySQL的各种锁机制,熟练其概念及在开发中正确使用是很有必要的。 我是少侠露飞,爱技术,爱分享。 祝大家国庆快乐!