MySQL之事务和锁

本文详细解释了事务的ACID特性,包括原子性、一致性、隔离性和持久性。特别关注了InnoDB引擎的行锁、间隙锁、元数据锁和全局锁,以及它们在并发控制中的作用。同时提到了SpringMVC和SpringBoot框架,但主要焦点在数据库技术上。
摘要由CSDN通过智能技术生成

传送门

SpringMVC的源码解析(精品)
Spring6的源码解析(精品)
SpringBoot3框架(精品)
MyBatis框架(精品)
MyBatis-Plus
SpringDataJPA
SpringCloudNetflix
SpringCloudAlibaba(精品)
Shiro
SpringSecurity
java的LOG日志框架
Activiti(敬请期待)
JDK8新特性
JDK9新特性
JDK10新特性
JDK11新特性
JDK12新特性
JDK13新特性
JDK14新特性
JDK15新特性
JDK16新特性
JDK17新特性
JDK18新特性
JDK19新特性
JDK20新特性
JDK21新特性
其他技术文章传送门入口

一、事务

ACID特性

Atomicity:原子性;将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行;
Consistency:一致性;事务完成后,所有数据的状态都是一致的,转账前后总和也是一致,即A账户只要减去了100,B账户则必定加上了100;
Isolation:隔离性;如果有多个事务并发执行,每个事务作出的修改必须与其他事务隔离;
Durability:持久性;即事务完成后,对数据库数据的修改被持久化存储。
对于单条SQL语句,数据库系统自动将其作为一个事务执行,这种事务被称为隐式事务。将一组SQL放在Begin和commit就是显式事务了。
jdbc默认情况下,我们获取到Connection连接后,总是处于“自动提交”模式,也就是每执行一条SQL都是作为事务自动执行的。只要关闭了Connection的autoCommit,那么就可以在一个事务中执行多条语句,事务以commit()方法结束。

隔离级别

Read Uncommitted读未提交:(事务还没提交,它做的变更就能被别的事务看到)会发生脏读,别个修改了还没提交就被你看到了,并且你还能读,就是脏读问题。
Read Committed读提交:(事务提交了,它做的变更才能被其他事务看到。真隔离了,但是受他人影响,他人修改前后在自己的整个事务中是动态变的)别个改之前你读了,别个改之后你又读了,两次不一样,发生了不可重复读问题。
Repeatable Read可重复读:(一个事务执行过程中看到的数据一直是这个事务开始时的数据,不会被其他事务操作这个数据而受到影响。不仅真隔离,还不会发生重复读问题,完全不受他人影响)别个insert之前你读不出,insert之后你也读不出,但是你update一次别个插入的那条数据然后就读出来了,发生了幻读问题。(同一个请求,后面请求比前面请求多了东西)这个是数据库默认隔离级别,一般都是用的这个级别。百度认为的幻读是这样的,查询同一个表,第一次查询三条,别的事务插入一条后,再次查询变成四条了(个人觉得百度百科不对,和廖雪峰演示的不一样)。
Serializable串行:所有事务按照次序依次执行,排队执行,上面的问题都不会发生,但是效率太慢了,没有重要情景一般不会用。
在MySQL中,如果使用InnoDB,默认的隔离级别是Repeatable Read。Oracle的默认隔离级别是Read Committed读提交,和MySQL不一样,所以Oracle迁移数据到MySQL的时候一定要设置MySQL隔离级别为读提交,才能保证数据隔离级别一致性。
备注:行锁的开始不是事务的开始,是update语句的时候开始的,结束确实是事务的结束。所以在一个事务中,update语句尽量往后面放,这样可以让获取行锁的影响降低到最小(锁等待),提高新能。
在这里插入图片描述

二、锁

InnoDB:默认使用,支持事务,行锁,支持外键约束,不支持全文索引,空间大小约为MyISAM的两倍;
MyISAM:早些年使用,不支持事务,表锁,不支持外键约束,支持全文索引,空间较小

表锁:

两个SQL去查同一个表,会把这个表锁定,反应慢;表锁的具体表现是读锁(共享锁,同一份数据,多个读操作互不影响,加了读锁容许其他事务继续获取这些记录的读锁,不能获取这些记录的写锁,会阻塞,有点类似不加是可读可写,加了变成了只读了)和写锁(独占锁,排他锁,当前写操作没有完成前,它会阻断其他写锁和读锁,加上写锁后不容许其他事务获取这些记录的读锁和写锁);在对某个表执行SELECT、INSERT、DELETE、UPDATE语句时MyISAM会增加表级别的读锁或者写锁;

行锁:

两个SQL去查同一个表,只会锁定查的行;有单独锁一条记录的,也有锁当前记录上下范围的不含本记录的间隙锁,还有记录当前记录上下范围含当前记录的锁;如果没有命中索引,行锁会变为表锁(5.5版本,新版本待确定?)

间隙锁:

是一种行锁,官方定义,当我们用范围条件条件检索数据(非聚簇索引、非唯一索引),并请求共享或排他锁时,InnoDB会给符合条件的数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,称为间隙,InnoDB也会为这些间隙加锁,即间隙锁。间隙锁在某些情况下可以解决幻读问题,比如update account set name = ‘zhuge’ where id > 10 and id <=20;,则其他Session没法插入或者更新这个范围内的数据,10到20整个数据范围被加了间隙锁(必须是可重复读的隔离级别,并且触发非聚集索引)

元数据锁:

在对某个表执行ALTER TABLE、DROP TABLE这些DDL语句时,其他事务对这个表执行SELECT、INSERT、 DELETE、UPDATE的语句会发生阻塞,或者,某个事务对某个表执行SELECT、INSERT、DELETE、UPDATE语句时,其他事务对这个表执行DDL语句也会发生阻塞。这个过程是通过使用的元数据锁(英文名:Metadata Locks,简称MDL)来实现的,并不是使用的表级别的读锁和写锁。随便给表增加字段,在高峰期是很危险的事情,因为很多查询要先拿到MDL锁(元数据锁)。
ALTER TABLE tbl_name NOWAIT add column …
ALTER TABLE tbl_name WAIT N add column … 增加个元数据锁的等待时间,超时还没加上的话,就失效,DBA去重复执行这条命令,这样不会导致堵塞后面要弄到MDL元数据锁的线程,就不会导致整个库奔溃。(wait n 中n单位为妙,wait 0等价于 nowait)
https://blog.csdn.net/cy973071263/article/details/104490345 (精品文章)

以下概念来自MySQL实战45讲,林晓斌,网名丁奇,前阿里资深技术专家

全局锁:

顾名思义,全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。全局锁的典型使用场景是,做全库逻辑备份。也就是把整库每个表都 select 出来存成文本。全局锁为什么会存在,是因为MyISAM引擎不支持事务,备份数据的时候就得用全局锁。而InnoDB这些引擎不用全局锁。

表级锁:

分成了表锁和元数据锁。概念对应前面的。

行级锁:

行锁就是针对数据表中行记录的锁。这很好理解,比如事务 A 更新了一行,而这时候事务 B 也要更新同一行,则必须等事务 A 的操作完成后才能进行更新。在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议(超级重点,行锁的开始和结束)。innodb行级锁是通过锁索引记录实现的。如果update的列没建索引,即使只update一条记录也会锁定整张表。所以在事务中,更新因为要获取行锁,所以放在最后面比较好,插入不获取行锁,可以放在前面。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝影铁哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值