数据库的事务与锁初理解

孤者浪人 提交于 2020-01-25 21:41:02

前沿: 以下内容大多来自以下三篇文章

-- 共享锁:
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事务实现原理

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!