前沿: 以下内容大多来自以下三篇文章
- Mysql事务与锁详解
- MySqL 事务与锁的深入学习笔记
- Mysql事务实现原理 (很推荐看下)
对于insert、update、delete,InnoDB会自动给涉及的数据加排他锁(X);对于一般的select语句,InnoDB不会加任何锁,事务可以通过以下语句给显式的加共享锁或排他锁。
-- 共享锁:
SELECT * from tb_user LOCK IN SHARE MODE;
-- 排他锁:
SELECT * from tb_user FOR UPDATE;
- 共享锁(S)
- 排它锁(X)
若某个事物对某一行加上了排他锁,只能这个事务对其进行读写,在此事务结束之前,其他事务不能对其进行加任何锁(如何执行的语句没有锁,那么就不会影响,比如默认的select语句就是没有任何锁的),其他进程可以读取,不能进行写操作,需等待其释放。 排它锁是悲观锁的一种实现
执行存储过程,开启事务,但是不提交,即锁一直在
CREATE DEFINER=`root`@`localhost` PROCEDURE `NewProc`()
BEGIN
start transaction;
set session transaction isolation level read committed;
SELECT name FROM a FOR UPDATE;
-- UPDATE a set name = '456' WHERE id = 1;
SELECT SLEEP(20);
-- commit; -- 语句1。必须主动提交
END
执行查询,任然可以查到,因为默认select没有锁,和排他锁不冲突,但是如果是跟新,删除语句默认是有锁的,就会冲突,而无法操作
SELECT * FROM a WHERE id = 1
但是如果你执意让select也带上锁,那么select也会冲突,而无法操作
SELECT * FROM a WHERE id = 1 FOR UPDATE;
当然你也可以忽略锁,执意执行(WITH(NOLOCK) 这只是在sqlserver中使用,mysql的请自行寻找),但是可能会出现脏数据,因为你没有等所有的锁释放,你就执行
SELECT * FROM a WITH(NOLOCK)
-
意向锁(IS,IX)
-
有意向锁的原因
表级别的意向锁是为了提高效率,我们能给一张表成功加上一个表锁的前提是:没有任何一个事务对这张表的某些行加了锁。如果没有意向表锁:如果现在要给一个表加上表锁。如果这张表有一千万行数据,需要全表扫描行,判断是否有事务锁定了某行! -
如何加?
意向锁是InnoDB自动加的,不需要用户干预。即如果某张表中的某行数据被加锁了,那么innerDB会自动在这张表上加上对应的锁(即如果被锁住的行是加的共享锁,那么表就加上意向共享锁,反之,如果被锁住的行是加的排它锁,那么表就加上意向排它锁),切记行级锁并不是直接锁记录,而是锁索引 -
死锁原因
行级锁的死锁
MyISAM中是不会产生死锁的,因为MyISAM总是一次性获得所需的全部锁,要么全部满足,要么全部等待。而在InnoDB中,锁是逐步获得的,就造成了死锁的可能。
在MySQL中,行级锁并不是直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,如果一条sql语句操作了主键索引,MySQL就会锁定这条主键索引; 如果一条语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引.在UPDATE、DELETE操作时,MySQL不仅锁定WHERE条件扫描过的所有索引记录,而且会锁定相邻的键值,即所谓的next-key locking。
当两个事务同时执行,一个锁住了主键索引,在等待其他相关索引。另一个锁定了非主键索引,在等待主键索引。这样就会发生死锁。
发生死锁后,InnoDB一般都可以检测到,并使一个事务释放锁回退,另一个获取锁完成事务。 -
出现死锁怎么办
-
间隙
-
事务与锁的关系
如果现在只有一个方法,只是操作一张表的一行数据
public CommonResult update(@RequestBody BottomMenuConf model) throws ParseException {
// 删除可能存在的VerLimit
VerLimit mb_verLimit = new VerLimit();
verLimitService.delete(mb_verLimit);
}
如果在这个sql语句执行的时候,马上又有一个跟新的sql语句,操作同一条数据,是无法操作的
但是一个方法会有多个sql语句,要保证所以涉及到的锁,要统一释放,
即用事务管理(说白了就是统一管理所有涉及到的数据库的锁,一荣俱荣一损俱损)
public CommonResult update(@RequestBody BottomMenuConf model) throws ParseException {
// 删除可能存在的VerLimit
VerLimit mb_verLimit = new VerLimit();
bottomMenuConfService.update(model);
}
最后还是强烈推荐大家看下 Mysql事务实现原理
来源:CSDN
作者:铛铛响
链接:https://blog.csdn.net/qq_38263083/article/details/103823516