事务
什么是事务
事务transaction(简写tx),在数据库中,事务是指一组逻辑操作,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。
事务由事务开始与结束之间执行的全部数据库操作组成。
事务的作用
保证了对数据操作的安全性,保证数据的一致性
例子:还钱的例子
- 还钱的账户数据减1000块钱
- 被还钱的账户数据增加1000块钱
在操作多条数据的时候可能会出现某几条数据操作不成功的情况
事务的四大特性
事务具有原子性、一致性、隔离性、持久性四大特性,简称ACID。
- 原子性(Atomicity):指事务是一个不可分割的最小工作单位,事务中的操作只有都发生和都不发生两种情况
- 一致性(Consistency):事务必须使数据库从一个一致状态变换到另外一个一致状态,举一个栗子,李二给王五转账50元,其事务就是让李二账户上减去50元,王五账户上加上50元;一致性是指其他事务看到的情况是要么李二还没有给王五转账的状态,要么王五已经成功接收到李二的50元转账。而对于李二少了50元,王五还没加上50元这个中间状态是不可见的。
- 隔离性(Isolation):一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持久性(Durability):一个事务一旦提交成功,它对数据库中数据的改变将是永久性的,接下来的其他操作或故障不应对其有任何影响。
注意:只有当前三条性质都满足了,才能保证事务的一致性
如何使用事务
事务相关的关键字
# 1. 开启事务
start transaction;
# 2. 回滚(回到事务执行之前的状态)
rollback;
# 3. 二次确认(确认之后就无法回滚了)
commit;
"""模拟转账功能"""
create table user(
id int primary key auto_increment,
name char(16),
balance int
);
insert into user(name,balance) values
('xiao',10000),
('quan',10),
('zheng',100);
# 1. 先开启事务
start transaction;
# 2. 多条SQL语句
update user set balance=9000 where name='xiao';
update user set balance=110 where name='quan';
update user set balance=1000 where name='zheng';
总结
当你想让多条SQL语句保持一致性,要么同时成功,要么同时失败,那么你就应该考虑使用事务。
小结
原子性,持久性大家基本都能秒懂,隔离性也还好大家稍微想想都能理解,就是接下来要讲的隔离级别,但对一致性很多人被官方概念绕住了,其实就是在多事务并发时要保证数据的一致和完整,不理解的话先看下面的问题。
事务并发带来的4类问题
1、脏读(Dirty Reads)
事务A读取到了事务B修改但尚未提交的数据,然后事务B回滚了,因此事务A基于此数据做的操作都是无效的,就是读到了“脏”数据(实际上不应该存在的数据),所以叫脏读。
2、脏写或丢失更新(Lost Update)
第一类丢失更新:撤销rollback一个事务时,把其他事务已经提交更新的数据回滚掉了。
第二类丢失更新:提交commit一个事务时,把其他事务已经提交更新的数据覆盖掉了。
3、不可重复读(Non-Repeatable Reads)
在事务A中,按相同的条件执行查询过的sql,返回结果发生了修改或被删除了,这种现象就叫做“不可重复读”。
4、幻读(Phantom Reads)
在事务A中,按相同的条件执行查询过的sql,返回结果中有新数据(是其它事务插入的),就好像发生了幻觉一样,这就叫“幻读”。
小结
不可重复读的和幻读很容易混淆,不可重复读侧重于修改或删除,幻读侧重于新增,大家请注意删除不属于幻读。
详细证明请参考
原文链接:https://blog.csdn.net/scm_2008/article/details/127985117
事务4种隔离级别
在SQL标准中定义了四种隔离级别,每一种级别都规定了一个事务中所做的修改,哪些是在事务内和事务间可见的,哪些是不可见的。较低级别的隔离通常可以执行更高的并发,系统的开销也更低。
每种隔离级别可能出现的问题如下:
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(RU) | 可能 | 可能 | 可能 |
读已提交(RC) | 不可能 | 可能 | 可能 |
可重复读(RR) | 不可能 | 不可能 | 可能 |
串行化(Serializable) | 不可能 | 不可能 | 不可能 |
1、读未提交(Read uncommitted,RU)
最低的隔离级别事务中的修改,即使没有提交,对其他事务也都是可见的,由于可能造成脏读,所以在实际应用中一般很少使用。
2、读已提交(Read committed,RC)
在这个级别下,一个事务只能读取到已经提交的数据,避免了脏读问题。大多数数据库系统的默认隔离级别都是读已提交(像Oracle、PostgreSQL、SqlServer,但Mysql不是)。
3、可重复读(Repeatable read,RR)
Mysql默认的事务隔离级别。在这个级别下,事务开始读取数据后,其他事务无法修改这些数据,保证了同一个事务内两次读取相同记录的一致性,所以解决了脏读和不可重复读问题,但未彻底解决幻读。
4、串行化(Serializable)
可串行化是最高的隔离级别。它通过强制事务串行执行,避免了前面所说的脏读,不可重复读和幻读问题。简单来说,可串行化会在读取的每一行数据上都加上锁,所以可能导致大量的超时和锁争用问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑用该级别。
MVCC机制
什么是MVCC机制
- MVCC是MySQL InnoDB存储引擎实现的一种基于多版本的并发控制协议,即多版本并发控制。
- 基于多版本的并发控制协议——MVCC (Multi-Version Concurrency Control) 。
MVCC的优势
- MVCC实现了读不加锁,避免了读写冲突,提高了系统的并发性能。
- MVCC解决了数据的脏读问题,保证了数据的一致性。
什么是当前读和快照读?
在学习MVCC多版本并发控制之前,我们必须先了解一下,什么是MySQL InnoDB下的当前读和快照读?
-
当前读
像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁)这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。
-
快照读
像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本
说白了MVCC就是为了实现读-写冲突不加锁,而这个读指的就是快照读, 而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现。
当前读,快照读和MVCC的关系
-
准确的说,MVCC多版本并发控制指的是 “维持一个数据的多个版本,使得读写操作没有冲突” 这么一个概念。仅仅是一个理想概念。
-
而在MySQL中,实现这么一个MVCC理想概念,我们就需要MySQL提供具体的功能去实现它,而快照读就是MySQL为我们实现MVCC理想模型的其中一个具体非阻塞读功能。而相对而言,当前读就是悲观锁的具体功能实现。
-
要说的再细致一些,快照读本身也是一个抽象概念,再深入研究。MVCC模型在MySQL中的具体实现则是由 3个隐式字段,undo日志 ,Read View 等去完成的,具体可以详细看看下面链接叙述的MVCC实现原理
原文链接:https://blog.csdn.net/suchahaerkang/article/details/109389291
标签:事务,快照,隔离,MySQL,并发,MVCC,级别 From: https://www.cnblogs.com/xiao01/p/18052699