mysql事务

事务要做到可靠性以及并发处理

可靠性:

数据库要保证当insert或update操作时抛异常或者数据库crash的时候需要保障数据的操作前后的一致。需要知道修改之前和修改之后的状态,所以就有了undo log和redo log。

并发处理:

当多个并发请求过来,并且其中有一个请求是对数据修改操作的时候会有影响,为了避免读到脏数据,所以需要对事务之间的读写进行隔离,至于隔离到啥程度得看业务系统的场景了,实现这个就得用MySQL 的隔离级别。
数据库层面:
实现事务功能的三个技术,分别是日志文件(redo log 和 undo log),锁技术以及MVCC,然后再说一下事务的实现原理。
1.日志文件:
1)redo log叫做重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都会存到该日志中。比如一个更新过程:
mysql事务_第1张图片
mysql 为了提升性能不会把每次的修改都实时同步到磁盘,而是会先存到Boffer Pool(缓冲池)里头,把这个当作缓存来用。然后使用后台线程去做缓冲池和磁盘之间的同步。如果,没来的同步的时候宕机或断电了,引入了redo log来记录已成功提交事务的修改信息,并且会把redo log持久化到磁盘,系统重启之后在读取redo log恢复最新数据。
总结:
redo log是用来恢复数据的 用于保障已提交事务的持久化特性。
2)undo log 叫做回滚日志,用于记录数据被修改前的信息。他正好跟前面所说的重做日志所记录的相反,重做日志记录数据被修改后的信息。undo log主要记录的是数据的逻辑变化,为了在发生错误时回滚之前的操作,需要将之前的操作都记录下来,然后在发生错误时才可以回滚。
每次写入数据或者修改数据之前都会把修改前的信息记录到 undo log。
总结:
记录事务修改之前版本的数据信息,因此假如由于系统错误或者rollback操作而回滚的话可以根据undo log的信息来进行回滚到没被修改前的状态。用来回滚数据的用于保障未提交事务的原子性。
2.mysql锁技术
当有多个请求来读取表中的数据时可以不采取任何操作,但是多个请求里有读请求,又有修改请求时必须有一种措施来进行并发控制。不然很有可能会造成不一致。
所以,需用两种锁的组合来对读写请求进行控制即可,这两种锁被称为:
共享锁,又叫做"读锁"
读锁是可以共享的,或者说多个读请求可以共享一把锁读数据,不会造成阻塞。
排他锁,又叫做"写锁"
写锁会排斥其他所有获取锁的请求,一直阻塞,直到写入完成释放锁
总结:
mysql事务_第2张图片
3.mvcc基础
多版本并发控制,通过在每行记录的后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存了行的过期时间,当然存储的并不是实际的时间值,而是系统版本号。他的主要实现思想是通过数据多版本来做到读写分离。从而实现不加锁读进而做到读写并行。

  • MVCC在mysql中的实现依赖的是undo log与read view
  • undo log :undo log 中记录某行数据的多个版本的数据。
  • read view :用来判断当前版本数据的可见性

4.事务的实现
重做日志,回滚日志以及锁技术就是实现事务的基础。
事务的原子性是通过undolog来实现的;持久性性是通过redolog来实现的
隔离性是通过(读写锁+MVCC);一致性是通过原子性,持久性,隔离性来实现的!!!
1)原子性:
一个事务必须被视为不可分割的最小工作单位,一个事务中的所有操作要么全部成功提交,要么全部失败回滚,对于一个事务来说不可能只执行其中的部分操作。回滚操作就是当发生错误异常或者显式的执行rollback语句时需要把数据还原到原先的模样,所以这时候就需要用到undo log来进行回滚。
mysql事务_第3张图片
总结:
1.每条数据变更(insert/update/delete)操作都伴随一条undo log的生成,并且回滚日志必须先于数据持久化到磁盘上
2.所谓的回滚就是根据回滚日志做逆向操作,比如delete的逆向操作为insert,insert的逆向操作为delete,update的逆向为update等。
2)持久性
事务一旦提交,其所做的修改会永久保存到数据库中,此时即使系统崩溃修改的数据也不会丢失。
MySQL的表数据是存放在磁盘上的,因此想要存取的时候都要经历磁盘IO,为了提升性能InnoDB提供了缓冲池(Buffer Pool),Buffer Pool中包含了磁盘数据页的映射,可以当做缓存来使用:

  1. 读数据:
    会首先从缓冲池中读取,如果缓冲池中没有,则从磁盘读取再放入缓冲池;

  2. 写数据:
    会首先写入缓冲池,缓冲池中的数据会定期同步到磁盘中;
    MySQL系统宕机,断电的时候可能会丢数据,数据已经提交了,但此时是在缓冲池里头,还没来得及在磁盘持久化,需一种机制需要存一下已提交事务的数据,为恢复数据使用。于是用到了redo log。
    既然redo log也需要存储,也涉及磁盘IO为啥还用它?
    (1)redo log 的存储是顺序存储,而缓存同步是随机操作。
    (2)缓存同步是以数据页为单位的,每次传输的数据大小大于redo log。

3)隔离性实现
在SQL标准里定义了四种隔离级别,每一种级别都规定一个事务中的修改,哪些是事务是否可见。
级别越低的隔离级别可以执行越高的并发,但同时实现复杂度以及开销也越大。
MySQL隔离级别有以下四种(级别由低到高):
READUNCOMMITED(未提交读)
READCOMMITED(提交读)
REPEATABLEREAD(可重复读)
SERIALIZABLE (串行化读)
隔离性是要管理多个并发读写请求的访问顺序。 这种顺序包括串行或者是并行。

  • 未提交读:

事务中的修改即使还没提交,对其他事务是可见的。读不会加任何锁,所以写操作在读的过程中修改数据,所以会造成脏读。
优点:可以提升并发处理性能,能做到读写并行。
缺点:造成脏读

  • 提交读:

一个事务的修改在他提交之前的所有修改,对其他事务都是不可见的。其他事务能读到已提交的修改变化。写数据采用排它锁(写锁),读取数据不加锁而是使用了MVCC机制,采用了读写分离机制。
缺点:会造成幻影读(两次查询的结果不一致)和不可重复读(MVCC机制有关系,在该隔离级别下每次 select的时候新生成一个版本号,所以每次select的时候读的不是一个副本而是不同的副本)。

  • 可重复读(Mysql默认隔离级别):

在一个事务内的多次读取的结果是一样的。这种级别下可以避免,脏读,不可重复读等查询问题。mysql 有两种机制可以达到这种隔离级别的效果,分别是采用读写锁以及MVCC。
可重复读:只要没释放读锁,在次读的时候还是可以读到第一次读的数据。
优点:实现起来简单
缺点:无法做到读写并行
采用MVCC实现:

  • 可重复读:因为多次读取只生成一个版本,读到的自然是相同数据。

优点:读写并行
缺点:实现的复杂度高,在该隔离级别下仍会存在幻读的问题

  • 串行化读:

该隔离级别理解起来最简单,实现也最简单。在隔离级别下除了不会造成数据不一致问题,没其他优点。

你可能感兴趣的:(mysql)