Mysql事务

MySQL事务

    什么是事务

    事务的四大特性

    MySQL的事务

事务隔离级别

    并发常见问题

    四大隔离级别

编码中的事务

事务的分类

事务的实现

    redo

    undo

    purge

    group commit

事务的控制语句

mysql事务

什么是事务

 事务(transaction)是数据库区别于文件系统的重要特性之一。

    银行转账!张三转10000块到李四的账户,这其实需要两条SQL语句:

    给张三的账户减去10000元;

    给李四的账户加上10000元。

    如果在第一条SQL语句执行成功后,在执行第二条SQL语句之前,程序被中断了(可能是抛出了某个异常,也可能是其他什么原因),那么李四的账户没有加上10000元,而张三却减去了10000元。这肯定是不行的!

    你现在可能已经知道什么是事务了吧!事务中的多个操作,要么完全成功,要么完全失败!不可能存在成功一半的情况!也就是说给张三的账户减去10000元如果成功了,那么给李四的账户加上10000元的操作也必须是成功的;否则给张三减去10000元,以及给李四加上10000元都是失败的!

     

    事务的四大特性(ACID

    事务的四大特性是:

    原子性(Atomicity):事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。

    一致性(Consistency):事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号余额之和应该是不变的。

    隔离性(Isolation):隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。

    持久性(Durability):一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。

     

    MySQL中的事务

    在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。

    开启事务:start transaction

    结束事务:commitrollback

    在执行SQL语句之前,先执行strat transaction,这就开启了一个事务(事务的起点),然后可以去执行多条SQL语句,最后要结束事务,commit表示提交,即事务中的多条SQL语句所做出的影响会持久化到数据库中。或者rollback,表示回滚,即回滚到事务的起点,之前做的所有操作都被撤消了!

事务隔离级别

并发事务问题

因为并发事务导致的问题大致有5类,其中两类是更新问题,三类是读问题。

脏读(dirty read):读到另一个事务的未提交更新数据,即读取到了脏数据;

不可重复读(unrepeatable read):对同一记录的两次读取不一致,因为另一事务对该记录做了修改;

幻读(虚读)(phantom read):对同一张表的两次查询不一致,因为另一事务插入了一条记录;

不可重复读和幻读的区别:

不可重复读是读取到了另一事务的更新;

幻读是读取到了另一事务的插入(MySQL中无法测试到幻读);

四大隔离级别

4个等级的事务隔离级别,在相同数据环境下,使用相同的输入,执行相同的工作,根据不同的隔离级别,可以导致不同的结果。不同事务隔离级别能够解决的数据并发问题的能力是不同的。

1SERIALIZABLE(串行化)

不会出现任何并发问题,因为它是对同一数据的访问是串行的,非并发访问的;

性能最差;

2REPEATABLE READ(可重复读)(MySQL

防止脏读和不可重复读,不能处理幻读问题;

性能比SERIALIZABLE

3READ COMMITTED(读已提交数据)(Oracle

防止脏读,没有处理不可重复读,也没有处理幻读;

性能比REPEATABLE READ

4READ UNCOMMITTED(读未提交数据)

可能出现任何事务并发问题

性能最好

MySQL隔离级别

MySQL的默认隔离级别为Repeatable read,可以通过下面语句查看:

select @@tx_isolation


也可以通过下面语句来设置当前连接的隔离级别:

set transaction isolationlevel [41]


编码中的事务

    重点: 事务的理解

    在代码开发中,业务逻辑类中的每一个public方法,都可以看成是一个事务 !

    业务逻辑层中的每一个public方法,都是一个交易

    强调: 事务操作中的多个步骤,这些必须要使用同一个connection对象,否则无法进行事务控制


事务的分类

本地事务(local transaction) :  事务管理器控制本地资源(数据库资源,消息中间件资源)

XA事务 (二段提交) :又叫JTA, 可以管理两个系统的资源 ,两段提交,两个资源不一定在本地

    可以是两个数据库系统,也可以是一个数据库+消息中间件。

    TUXEDO(BEA公司) -->> WebLogic ,  EJB

声明式事务:spring

分布式事务:  BASE, MOM(异步通讯)


MySQL阶段三——MySQL事务_mysql


事务的实现

redo log称为重做日志,用来保证事务的原子性和持久性。undo log用来保证事务的一致性。

一、redo

基本概念

    其由两部分组成:一是内存中的重做日志缓冲,其是易丢失的;而是重做日志文件、其是持久的。

    每个InnoDB 存储引擎至少有1 个重做日志文件组(group),每个文件组下至少有2 个重做日志文件,如默认的ib_logfile0 和ib_logfile1。为了得到更高的可靠性,用户可以设置多个的镜像日志组(mirrored log groups),将不同的文件组放在不同的磁盘上,以此提高重做日志的高可用性。在日志组中每个重做日志文件的大小一致,并以循环写入的方式运行。InnoDB 存储引擎先写重做日志文件1,当达到文件的最后时,会切换至重做日志文件2,再当重做日志文件2 也被写满时,会再切换到重做日志文件1 中。

    下列参数影响着重做日志文件的属性:

  • innodb_log_file_size

  • innodb_log_files_in_group

  • innodb_mirrored_log_groups

  • innodb_log_group_home_dir

参数innodb_log_file_size 指定每个重做日志文件的大小。在InnoDB1.2.x 版本之前,重做日志文件总的大小不得大于等于4GB,而1.2.x 版本将该限制扩大为了512GB。

参数innodb_log_files_in_group 指定了日志文件组中重做日志文件的数量,默认为2。

参数innodb_mirrored_log_groups 指定了日志镜像文件组的数量,默认为1,表示只有一个日志文件组,没有镜像。


    重做日志文件的大小设置对于InnoDB 存储引擎的性能有着非常大的影响。一方面重做日志文件不能设置得太大,如果设置得很大,在恢复时可能需要很长的时间;另一方面又不能设置得太小了,否则可能导致一个事务的日志需要多次切换重做日志文件。此外,重做日志文件太小会导致频繁地发生async checkpoint,导致性能的抖动。


也许有人会问,既然同样是记录事务日志,和之前介绍的二进制日志有什么区别?

    首先,二进制日志会记录所有与MySQL 数据库有关的日志记录,包括InnoDB、MyISAM、Heap 等其他存储引擎的日志。而InnoDB 存储引擎的重做日志只记录有关该存储引擎本身的事务日志。

    其次,记录的内容不同,无论用户将二进制日志文件记录的格式设为STATEMENT还是ROW,又或者是MIXED,其记录的都是关于一个事务的具体操作内容,即该日志是逻辑日志。而InnoDB 存储引擎的重做日志文件记录的是关于每个页(Page)的更改的物理情况。

    此外,写入的时间也不同,二进制日志文件仅在事务提交前进行提交,即只写磁盘一次,不论这时该事务多大。而在事务进行的过程中,却不断有重做日志条目(redoentry)被写入到重做日志文件中。


在InnoDB 存储引擎中,对于各种不同的操作有着不同的重做日志格式。到InnoDB1.2.x 版本为止,总共定义了51 种重做日志类型。虽然各种重做日志的类型不同,但是它们有着基本的格式:

MySQL阶段三——MySQL事务_sql语句_02


写入重做日志文件的操作不是直接写,而是先写入一个重做日志缓冲(redo log buffer)中,然后按照一定的条件顺序地写入日志文件。

MySQL阶段三——MySQL事务_sql语句_03

从重做日志缓冲往磁盘写入时,是按512 个字节,也就是一个扇区的大小进行写入。因为扇区是写入的最小单位,因此可以保证写入必定是成功的。因此在重做日志的写入过程中不需要有doublewrite。


    主线程(master thread),知道在主线程中每秒会将重做日志缓冲写入磁盘的重做日志文件中,不论事务是否已经提交。另一个触发写磁盘的过程是由参数innodb_flush_log_at_trx_commit 控制,表示在提交(commit)操作时,处理重做日志的方式。

    参数innodb_flush_log_at_trx_commit 的有效值有0、1、2。0 代表当提交事务时,并不将事务的重做日志写入磁盘上的日志文件,而是等待主线程每秒的刷新。1 和2 不同的地方在于:1 表示在执行commit 时将重做日志缓冲同步写到磁盘,即伴有fsync 的调用。2 表示将重做日志异步写到磁盘,即写到文件系统的缓存中。因此不能完全保证在执行commit 时肯定会写入重做日志文件,只是有这个动作发生。

    因此为了保证事务的ACID 中的持久性,必须将innodb_flush_log_at_trx_commit 设置为1,也就是每当有事务提交时,就必须确保事务都已经写入重做日志文件。那么当数据库因为意外发生宕机时,可以通过重做日志文件恢复,并保证可以恢复已经提交的事务。而将重做日志文件设置为0 或2,都有可能发生恢复时部分事务的丢失。不同之处在于,设置为2 时,当MySQL 数据库发生宕机而操作系统及服务器并没有发生宕机时,由于此时未写入磁盘的事务日志保存在文件系统缓存中,当恢复时同样能保证数据不丢失。


二、undo

Undolog:在操作任何数据之前,首先将数据备份到一个地方(undolog),然后再修改;这样就算更改到一半的时候,出现意外更改没有完成,则还可以恢复原来数据。

MySQL阶段三——MySQL事务_记录_04

MySQL阶段三——MySQL事务_信息_05


undo log格式:insert undo log、update undo log;


三、purge

MySQL阶段三——MySQL事务_sql语句_06

四、group commit



MySQL阶段三——MySQL事务_sql语句_07