数据库的锁
锁分为乐观锁和悲观锁。
其中悲观锁按照类型可以划分为:
- 共享锁(读锁)
- 排他锁(写锁)
也可以按照锁的范围分为:
- 行锁
- 表锁
乐观锁
假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。
乐观锁是一种不会阻塞其他线程并发的控制,它不会使用数据库的锁进行实现,它的设计里面由于不阻塞其他线程,所以并不会引起线程频繁挂起和恢复,这样便能够提高并发能力,所以也有人把它称为非阻塞锁。
一般的实现乐观锁的方式就是记录数据版本。(数据版本:为数据增加的一个版本标识。)
当读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为是过期数据。
实现数据版本有两种方式,第一种是使用版本号,第二种是使用时间戳。
使用版本号实现乐观锁:
使用版本号时,可以在数据初始化时指定一个版本号,每次对数据的更新操作都对版本号执行+1操作。并判断当前版本号是不是该数据的最新的版本号。
1 | 1.查询出商品信息 |
悲观锁
假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。
悲观锁是一种利用数据库内部机制提供的锁的方式,也就是对更新的数据加锁,这样在并发期间一旦有一个事务持有了数据库记录的锁,其他的线程将不能再对数据进行更新了,这就是悲观锁的实现方式。
行锁
MySQL 5.6 以后Engine db 默认是行锁,当然Engine也支持表锁,mysql InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型
表锁
MySQL 的MyISAM 的默认锁为表锁,当数据库表设置为MyISAM后,操作该数据库都会加表锁,其中 查询数据会加读锁(共享锁),修改、增加、删除数据会加写锁(排他锁)
1 | # 由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL才会执行Row lock (只锁住被选取的资料例) ,否则MySQL将会执行Table Lock (将整个资料表单给锁住): |
排他锁(写锁)
sql语句:select ...for update
如果一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行共享锁和排他锁只有获取到排它锁的事务支持对数据行的修改。
共享锁(读锁)
sql语句:select ... lock in share mode
共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
举例
举例,使用排他锁
1 | //0.开始事务 |
需要注意,innodb默认的锁级别是行锁
部分转载自:https://www.yuque.com/fanzhengxu/tba6b8/dx0hvw#eDkqD