MySQL 事务(4)

Wesley13
• 阅读 746

什么是事务?

数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。

这里有两个关键点,第一,它是数据库最小的工作单元,是不可以再分的。第二,它可能包含了一个或一系列DML语句,包括insert delete update。(单条DDL(create drop) 和DCL(grant revoke)也会有事务)

事务的四大特性(ACID)

特性

说明

原子性(Atomicity)

事务中的全部操作在数据库中是不可分割的,要么全部完成,要么全部不执行。

一致性(Consistent)

几个并行执行的事务,其执行结果必须与按某一顺序 串行执行的结果相一致。

隔离性(Isolation)

事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。

持久性(Durability)

对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。

原子性(Atomicity)

以转账为例,一个账户的余额减少,对应一个账户增加这两个一定是同时成功或同时失败。

全部成功好理解,问题是如果前一个操作已经成功,后一个操作失败了,如何让他全部失败呢?这时候我们必须要回滚。

原子性,在InnoDB里面是通过undo log来实现的,它记录了数据之前的值(逻辑日志),一旦发生异常,就可以用undo log来实现回滚操作。

一致性(Consistent)

还以转账为例,A账户余额有500元,这时有两个转账请求过来,都要转账500元,如果两个请求都执行成功,A账户的余额就成-500元,但这是错误的,储蓄卡的余额是不能小于0的,所以违反了一致性。完整性通常需要用户在代码中控制。

隔离性(Isolation)

有了事务的定义以后,在数据库里面会有很多的事务同时去操作我们的同一张表或者同一行数据,必然会产生一些并发或者干扰的操作,那么我们对隔离性的定义,就是这些很多个的事务,对表或者行的并发操作,应该是透明的,互相不干扰的。通过这种方式,我们最终也是保证业务数据的一致性。

像一致性的转账例子,应该是第一个事务转账成功,第二个事务提示余额不足。

持久性(Durability)

事务的持久性是什么意思呢?我们对数据库的任意的操作,增删改,只要事务提交成功,那么结果就是永久性的,不可能因为我们系统宕机或者重启了数据库的服务器,它又恢复到原来的状态了。这个就是事务的持久性。可以理解为数据已被写入到存储介质上。

持久性怎么实现呢?数据库崩溃恢复(crash-safe)是通过什么实现的?

持久性是通过redo log和double write双写缓冲来实现的,我们操作数据的时候,会先写到内存的buffer pool里面,同时记录redo log,如果在刷盘之前出现异常,在重启后就可以读取redo log的内容,写入到磁盘,保证数据的持久性。

当然,恢复成功的前提是数据页本身没有被破坏,是完整的,这个通过双写缓冲(double write)保证。

原子性,隔离性,持久性,最后都是为了实现一致性。

事务并发会遇到哪些问题?

当很多事务并发操作数据库的表或行时,如果没有我们刚才讲的事务隔离性时,会带来哪些问题?

MySQL  事务(4)

如上图有两个事务,事务A先查询id=1的这行数据,之后事务B修改age=18,但未提交,此时事务A再次查询id=1的数据,这行数据age变成了18。这种在一个事务里,由于其他事务修改了数据并没有提交,而导致了前后两次读取数据不一致的情况,这种事务并发问题,我们将之定义为脏读

如果在转账案例里面,我们第一个事务读取到第二个事务未提交的余额进行了操作,但第二个事务进行了回滚,这个时候会导致数据不一致。

这种读取其他事务未提交的数据情况,我们叫做脏读

MySQL  事务(4)

同样两个事务,A事务通过id=1查到一条数据。然后在第二个事务里执行一个update操作,并且修改了提交。然后A事务继续查询id=1的数据,此时A事务的前后两次查询数据不一致,像这种age到底等于16还是18,那么这种事务并发带来的问题,我们定义为不可重复读

这种一个事务读取到了其他事务已提交的数据导致前后两次读取数据不一致的情况,我们把它叫做不可重复读。

MySQL  事务(4)

在上图中,我们在A事务中执行了一个范围查询,这个时候满足条件的数据只有一条。在B事务里面插入了一行新数据,并且提交了。此时在A事务再次查询时,会发现多了一条数据。这种情况我们定义为幻读

不可重复读和幻读的区别在哪里?

不可重复读是修改或者删除,幻读是插入。

小结:上边说的三大问题。无论是脏读、不可重复读、幻读,都是数据库的读一致性问题,都是在一个事务前后两次读取出现了不一致的情况。

读一致性的问题,必须要由数据库提供一定的事务隔离机制来解决。就像我们去饭店吃饭,基本的设施和卫生保证都是饭店提供的。那么我们使用数据库,隔离性的问题也必须由数据库帮助我们来解决。

MySql InnoDB 事务隔离级别

在MySQL InnoDB里面,不需要使用串行化的隔离级别去解决所有问题。我们来看一下MySQL InnoDB里面对数据库事务隔离级别的支持程度是什么样的。

事务隔离级别

脏读

不可重复读

幻读

未提交读(Read Uncommitted)

可能

可能

可能

已提交读(Read Committed)

不可能

可能

可能

可重复读(Repeatable Read)

不可能

不可能

对InnoDB不可能

串行化(Serializable)

不可能

不可能

不可能

InnoDB支持的四个隔离级别和SQL92定义的基本一致,隔离级别越高,事务的并发度就越低。唯一的区别就在于,InnoDB在RR的级别就解决了幻读的问题。这个也是InnoDB默认使用RR作为事务隔离级别的原因,既保证了数据的一致性,又支持较高的并发度。

实现方案

如果要解决读一致性的问题,保证一个事务中前后两次读取数据结果一致,实现事务隔离,你会怎么做?

一、基于锁的并发控制LBCC(Lock Based Concurrency Control)

既然要保证前后两次读取数据一致,那么我读取数据的时候,锁定我要操作的数据,不允许其他事务修改就行了。这种方案我们叫做基于锁的并发控制

如果仅仅是基于锁来实现事务隔离,一个事务读取的时候不允许其他时候修改,那就意味着不支持并发的读写操作,而大多数应用都是读多写少的,这样会极大地影响操作数据的效率。

二、多版本的并发控制 MVCC(Multi Version Concurrency Control)

如果要让一个事务前后两次读取的数据保持一致,那么我们可以在修改数据的时候给他建立一个备份或者叫快照,后面再来读取这个快照就行了。这种方案我们叫做多版本的并发控制

MVCC的核心思想是:我可以查到在我这个事务开始之前已经存在的数据,即使它在后面被修改或者删除了。在我这个事务之后新增的数据,我是查不到的。

那么这个快照什么时候创建?读取数据的时候,怎么保证能读取到这个快照而不是最新的数据?该如何实现?

InnoDB为每行记录都实现了4个隐藏字段:

字段名

长度

说明

DB_ROW_ID

6字节

行标识

DB_TRX_ID

6字节

插入或更新行的最后一个事务的事务ID,事务编号是自动递增的(可以理解为创建版本号,在数据新增或者修改为新数据的时候,记录当前事务ID)。

DB_ROLL_PTR

7字节

回滚指针(可以理解为删除版本号,数据被删除或记录为旧数据的时候,记录当前事务ID)。

DELETE_FLAG

删除标记

MySQL  事务(4)

通过以上演示,通过事务ID的控制,无论其他事务是插入、修改、删除,第一个事务查询到的数据都没有变化。

可以将各事务中的查询逻辑按以下条件理解

select * from user_innoDB 
where DB_TRX_ID <= 2 or DB_ROLL_PTR <= 2;

隔离级别

事务隔离级别

脏读

不可重复读

幻读

未提交读(Read Uncommitted)

可能

可能

可能

已提交读(Read Committed)

不可能

可能

可能

可重复读(Repeatable Read)

不可能

不可能

对InnoDB不可能

串行化(Serializable)

不可能

不可能

不可能

Read Uncommitted (RU)

RU隔离级别:不加锁。

Serializable

Serializable所有select语句都会被隐式的转化为select ... in share mode ,会和update、delete互斥。

Repeatable Read(RR)

RR隔离级别下,普通的select 使用快照读(snapshot read),底层使用MVCC来实现。

加锁的select 以及更新操作update、delete等语句使用当前读(current read),底层使用记录锁、间隙锁、临键锁

Read Committed(RC)

RC隔离级别下,普通的select 都是快照读,使用MVCC实现。

加锁的select 都使用记录锁,因为没有Gap Lock。

除了两种特殊情况

  1. 外检约束检查(foreign-key constraint checking)
  2. 重复键检查(duplicate-key checking)

以上两种会使用间隙锁封锁区间。所以RC会出现幻读的问题。

事务隔离级别如何选择?

RU和Serializable肯定不能用。为什么有些公司要用RC?

RC和RR的主要有几个区别:

  1. RR的间隙锁会导致锁定范围的扩大。
  2. 条件列未使用到索引,RR锁表,RC锁行。
  3. RC的“半一致性”(semi-consistent)读可以增加update操作的并发性。

在RC中,一个update语句,如果读到一行已经加锁记录,此时InnoDB返回记录最近提交的版本,由MySQL上层判断此版本是否满足update的where条件。若满足(需要更新),则MySQL会重新发起一次读操作,此时会读取行的最新版本(并加锁)。

实际上,如果能够正确地使用锁(避免不使用索引加锁),只锁定需要的数据,用默认的RR级别就可以。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
LosAngel LosAngel
3年前
golang实现MySQL数据库事物的提交与回滚
MySQL事务主要用于处理操作量大,复杂度高的数据。在MySQL中只有使用了Innodb数据库引擎的数据库或表才支持事务。事务用来管理insert,update,delete语句,事务处理可以用来维护数据库的完整性,保证成批的SQL语句要么全部执行,要么全部不执行。一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicit
Stella981 Stella981
3年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Easter79 Easter79
3年前
Spring事务(二):Spring事务的特点
事务特性实现事务必须满足以下四大特性:Atomicity(原子性):构成事务的的所有操作必须是一个逻辑单元,要么全部执行,要么全部不执行。Consistency(一致性):数据库在事务执行前后,完整性没有被破坏。(转账前后,钱的总数不变)Durability(持久性):事务执行成功后必须全部写入磁盘。
Wesley13 Wesley13
3年前
mysql 事物四大特性和事物的四个隔离
1、事物四大特性(ACID)1.原子性(atomicity):一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。2.一致性(consistency):数据库总数从一个一致性的状态转换到另一个一致性的状态。3.隔离性
Wesley13 Wesley13
3年前
MySQL transaction
MySQLtransaction(数据库的事务)数据库事务(DatabaseTransaction),是指作为单个逻辑工作单元执行的一系列操作。要么完全执行,要么完全地不执行。ACID事务必须具备ACID四个特性原子性(Atomicity)原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。一致性(Consistency)
Wesley13 Wesley13
3年前
Mysql系列第十五讲 事务详解
Mysql系列第十五讲什么是事务?事务的几个特性(ACID)Mysql中事务操作savepoint关键字只读事务事务中的一些问题事务的隔离级别关于隔离级别的选择什么是事务?数据库中的事务是指对数据库执行一批操作,这些操作最终要么
Wesley13 Wesley13
3年前
MySQL常见问题
事务四大特性原子性:不可分割的操作单元,事务中所有操作,要么全部成功;要么撤回到执行事务之前的状态一致性:如果在执行事务之前数据库是一致的,那么在执行事务之后数据库也还是一致的;隔离性:事务操作之间彼此独立和透明互不影响。事务独立运行。这通常使用锁来实现。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。
Wesley13 Wesley13
3年前
Mysql事务,并发问题,锁机制
1、什么是事务事务是一条或多条数据库操作语句的组合,具备ACID,4个特点。原子性:要不全部成功,要不全部撤销隔离性:事务之间相互独立,互不干扰一致性:数据库正确地改变状态后,数据库的一致性约束没有被破坏持久性:事务的提交结果,将持久保存在数据库中2、事务并发会产生什么问题1)第一类丢失更新:在没有事务隔离的情况下,两个事务都同时