锁
mysql并发事务访问相同记录
2.1 读读情况
读-读 情况,即并发事务相继 读取相同的记录 。读取操作本身不会对记录有任何影响,并不会引起什么问题,所以允许这种情况的发生。
2.2 写写情况
写-写 情况,即并发事务相继对相同的记录做出改动。
脏写:
A,B同时操作某一条记录,A对改记录修改,原来值为1改为2了,但是B这是也对改记录进行修改 改为3但是B将事务回滚了,这是就发生了脏写
在这种情况下会发生 脏写 的问题,任何一种隔离级别都不允许这种问题的发生。所以在多个未提交事务相继对一条记录做改动时,需要让它们 排队执行 ,这个排队的过程其实是通过 锁 来实现的。这个所谓的锁其实是一个 内存中的结构 ,在事务执行前本来是没有锁的,也就是说一开始是没有 锁结构 和记录进行关联的,如图所示:
当一个事务想对这条记录做改动时,首先会看看内存中有没有与这条记录关联的 锁结构 ,当没有的时候就会在内存中生成一个 锁结构 与之关联。比如,事务 T1 要对这条记录做改动,就需要生成一个 锁结构与之关联:
一个事务对应一个锁结构,当前事务没结束是,另一个事务又来这是会再次生成一个锁结构
2.3 读写
读-写 或 写-读 即一个事务进行读取操作,另一个进行改动操作。这种情况下可能发生脏读 ,不可重复读 幻读的问题。
各个数据库厂商对SQL标准 的支持都可能不一样。比如MySQL在REPEATABLE READ 隔离级别上就已经解决了幻读问题。
2.4解决方案
从数据操作的类型划分:读锁 写锁
锁定读
select ... from 表名 lock in share mode //为读取到的数据添加共享锁
select ... from 表名 for update //加排它锁
#事务1
begin
SELECT * FROM student LOCK IN SHARE MODE
#事务二
begin
SELECT * FROM student LOCK IN SHARE MODE
#成功 此时commit事务二
commit
begin
SELECT * FROM student for update #失败 因为事务1 对该数据加了共享锁
#X锁 加X锁 也会被阻塞
#X锁 加S锁 也会被阻塞
写操作必须加排它锁
从数据操作的粒度划分
表锁
表级别的S和X锁
意向锁
在我们对行数据加锁是会自动在其外层空间结构加一个意向锁 IX
这样可以方便告知这个数据页有数据加过锁了
如果对表中一条数据加过X锁,那么另一个会话对表加锁是阻塞,因为意向锁(自动对表级别加IX)
意向锁不会与行级的共享 / 排他锁互斥!正因为如此,意向锁并不会影响到多个事务对不同数据行加排
他锁时的并发性。(不然我们直接用普通的表锁就行了)
比如对一个id=5数据加行锁,自动会对整个表加一个意向锁IX,这是另一个事务对id=6加锁是不受影响的
自增锁
元数据锁(MDL)锁
MDL的读锁之间是可以同时增删查改的 ,但是如果有一个MDL写锁这是就会阻塞
比如我们遇到一种情况 一个事务正在读一个表的内容这时会加MDL的读锁,这时另一个事务要更改表结构这时要加MDL的写锁,这个事务被阻塞了。这时又来一个事务要读,这时就会阻塞
行锁
InnoDB与MyISAM最大区别:①支持索引 ②采用行级锁
#事务1
begin
update student set name='测试' where id=1 #这是mysql会自动给改行加上X锁
#事务2
begin
select * from student where id=1 #可以读到
select * from student where id=1 lock in share mode #阻塞
#直到事务1 commit才能读取到
间隙锁
可以多次去加
临键锁