根据粒度
可以分为行锁、页锁、表锁。
行锁是加在某条记录上,其余事务不能修改该条记录,但能修改其他记录;
表锁是加在某张表上,其余事务不能修改这张表的任何数据;
页锁是介于行锁和表锁之间,加在数据页上;
什么时候用到行锁、表锁
查询条件里面用到索引,是行锁;
查询条件没有用到索引,是表锁;
示例:
新建一张表student,id是主键,Age是唯一键,Name没有添加;
我们开2个tab窗口,每个窗口都去设置:
set @@autocommit = 0;
这样子控制事务的手动提交(执行commit或rollback),可以用select @@autocommit;来查看一下
没有用到索引:
此处使用到索引:
根据使用方式
可以分为读锁和写锁
-
读锁
- select … lock in share mode 写锁
- select … for update
加上读锁后,其余事务也能加读锁,但不能加写锁;
加上写锁后,其余事务不能加读锁,也不能加写锁;
但读锁也会造成死锁问题
根据思想
悲观锁、乐观锁
悲观锁:认为每次操作都是有其他线程的,所以都要先取加锁;能够加锁就继续执行,不能加锁就阻塞等待;以上的select … lock in share mode、select … for update都是乐观锁
乐观锁:认为每次操作没有其余线程,当要进行提交时,才去进行比较;事务一开始时,取出version字段,当要进行提交事务时,再去取出当前version字段,如果相等则提交事务,不相等则重新执行。
间隙锁
数据库中会有幻读问题,如何解决:可串行化隔离级别和间隙锁来控制;
间隙锁和行锁对应,行锁是锁住某条数据,间隙锁是锁住范围,不让其余事务插入。
next-key锁是行锁+间隙锁
普通索引,=、<、<=、>、>=都是next-key锁
主键索引和唯一索引用=,查询到数据是行锁,查询不到数据是间隙锁(两边都是开区间),用<、<=、>、>=是next-key锁
例:
age字段建立唯一索引,有如下数据:1,4,8,12,16:
age < 6、<= 6、< 8,锁住了(-无穷,8]和<= 8的行锁
age <= 8,锁住了(-无穷,12]和<= 12的行锁
age > 10、>= 10、> 8,锁住了(8,+无穷]和>8的行锁
age >= 8,锁住了(4,+无穷]和>4的行锁
age字段建立普通索引,还是以上数据:
age = 6,锁住了[4,8)
age = 8,锁住了[4,12)和8这一行锁
age < 6、<= 6、< 8,锁住了[-无穷,8)和<= 8的行锁
age <= 8,锁住了[-无穷,12)和<= 12的行锁
age > 10、>= 10、> 8,锁住了[8,+无穷)和>8的行锁
age >= 8,锁住了[4,+无穷)和>4的行锁