mysql事务

1.事务概述

事务是一种机制,也可称为是一个执行单元,执行单元里面包含多条SQL语句,这些SQL语句要么全部执行成功,要么都不成功,不可分割。在mysql数据库中只有用Innodb引擎的表才能使用事务,而且默认自动提交事务。

2.事务特性(ACID)

  • 原子性:事务不可在分割的原则称为原子性,SQL语句要么全部执行成功,要么全部失败。
  • 一致性:在事务前——事务后,数据必须按照原则保证完整性。
  • 隔离性:防止并发情况下多个事务操作数据而导致数据的实际结果不一样。
  • 持久性:当事务结束后,对数据的修改就是永久的,因为数据保存在磁盘

 3.多个事务并发可能会产生的问题

3.1脏读 

对于事务T1和T2,如果T1读取了T2事务中还未提交的数据,那么这个数据就是脏数据。比如A账户有100元,此时T1和T2同时开启事务,T2事务将A账户充值50元,那么此时T1读取到的A账户为150元,但是此时T2出现问题了,发生了回滚,A账户实际还是只有100元,那么这个T1读到的150就是一条脏数据。

3.2不可重复读

对于事务T1和T2,如果在事务T1中多次读到的同一数据不一致,那么就是不可重复读。比如A账户有100元,此时T1和T2同时开启事务,T1第一次读A账户为100元,此时T2在A账户充值50元,并提交了T2事务(注意T2已经提交了事务,所以不会发生脏读)。然后T1再读取A账户,发现为150元,那么在T1这个事务中,还未提交事务T1前读取两次A账户会有两个不同的结果。

3.3幻读

此时用户表中总共有5条数据,此时T1和T2同时开启事务,T1第一次读到表中数据有5条,此时T2在用户表中新增了一条数据,并提交了T2事务,此时T1再次读取用户表发现数据有6条,那么在T1这个事务中,还未提交事务T1前读取两次用户表中的数据条数不一样,这就是幻读。

 不可重复侧重于数据的修改,而幻读侧重与数据的添加或者删除对数据条数发生的变化。

 4.事务的隔离级别

事务的隔离级别来解决并发事务时出现的问题,不同的隔离级别可以解决不同的问题,隔离级别越高,一致性就越强。mysql事务的隔离级别有读未提交、读已提交、可重复读、串行化。mysql默认使用的是可重复读。

事务隔离级别 脏读 不可重复读 幻读
读未提交 会出现 会出现 会出现
读已提交 不会出现 会出现 会出现
可重复读 不会出现 不会出现 会出现
串行化(通过锁表实现,效率太低) 不会出现 不会出现 不会出现

 mysql默认不使用串行化的原因是会严重影响效率,因为要锁表,相当于是单线程操作。

5.事务内部的实现原理 (重点)

 5.1需要实现的核心问题

        事务无非就是要保证可靠性并发处理,可靠性就是我们必须记录数据修改前和修改后的状态,为回滚做保证。并发处理就是多个事务同时操作数据时,各个事务必须隔离起来操作,需要使用事务的隔离级别。

5.2实现事务功能需要用到的三个技术 

5.2.1日志文件(redo log和undo log)

BUffer Poll:mysql的表数据都是存放在磁盘上的,为了提升读写性能Innodb提供了缓冲池(Buffer Poll),Buffer Poll中存储了磁盘数据页的映射,读取时先从缓存中读取,如果没有,则从磁盘中读取,之后放入缓冲池。

redolog是为了保证数据的持久性,分为内存日志缓冲磁盘日志,mysql为了提升性能对于每次修改并不会立即的同步到磁盘中,而是先存在Buffer Poll缓冲池中并将修改记录存在内存的redo log当中并转到磁盘的redo log中,然后后台的线程才会去做缓冲池和磁盘的数据同步,如果此时宕机了,那么在重启后会读取redolog来恢复数据,来保证数据的一致性。

undolog是为了保证数据的原子性,undolog也叫回滚日志,记录的是数据修改前的信息,新增的信息和删除的信息,为的是在发生错误的时候可以回滚到没被修改之前的状态。

5.2.2mysql锁技术

mysql在并发事务读取数据和修改数据下,可以使用读写锁来进行控制,不然很难保证事务的隔离性。这两种锁为共享锁和排他锁。其使用关系如下:

共享锁 排他锁
共享锁 可并行使用 不可并行使用
排他锁 不可并行使用 不可并行使用

5.2.3MVCC

MVCC叫做多版本并发控制,实现思想是通过数据多版本来做到读写分离,从而做到不加锁来实现读写并行,MVCC的实现依靠的是undo log和read view。Innodb中的MVCC是通过在每行记录后面保存两个隐藏的列来实现的,一个保存了行的事务ID另一个保存了行的回滚版本编号。

  • 行的事务ID:每次有事务对此行数据改动时,都会将此事务ID赋值。
  • 行的回滚版本编号:每次对此记录进行改动时,都会把旧版本写入到undo log日志中,根据回滚版本编号就可以找到修改前的信息,随着版本的增多,所有版本会链接为链表,称为版本链。如下图:

mysql事务_第1张图片

 ReadView是一个用于MVCC的数据快照,用于保存这某个时刻的数据信息。

        在实现读已提交的隔离级别中,可利用排他锁来解决脏读问题,在此隔离级别下的MVCC每次读取都会生成新的ReadView,每次读取的是最新的数据,也称为当前读。

        在实现可重复读的隔离级别中,在此隔离级别下的MVCC当一个事务第一次读取时,就会生成ReadView,第二次查询时仍然会从当前ReadView中读数据

事务的隔离性是通过读写锁+MVCC来实现的。

事务的一致性是靠原子性、持久性和隔离性来共同保证的!

你可能感兴趣的:(mysql,mysql,数据库)