【MYSQL】Mysql事务

 

 事务介绍

  1. 事务是数据库系统区别其他一切文件系统的重要特征。文件系统不能保证修改两个文件保存内容一致。

  2. 事务是由一组具有原子性的sql语句或者是一个独立的工作单元。可以是一个sql,或者有多个增删改查组成的sql语句集合。

  3. 事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元)
一个完整的业务需要批量的DML(insert、update、delete)语句共同联合完成

 

 

Mysql事务的特性四个特性(ACID)

  1. 原子性(Atomicity,或称不可分割性):事务中所有的操作,要么都执行成功,要么其中有一条失败就全部都不执行

  2. 一致性(Consistency)

  3. 隔离性(Isolation)

  4. 持久性(Durability)

 

   在 MySQL 中,事务支持是在引擎层实现的。

   并不是所有引擎都支持事务,如 MyISAM 就不支持,InnoDB 就支持;

 

 

事务并发的问题

    1.  脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态。这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做"脏读"。

    2. 不可重复读(Non-Repeatable Reads):一个事务读取某些数据,在它结束读取之前,另一个事务可能完成了对数据行的更改。当第一个事务试图再次执行同一个查询,服务器就会返回不同的结果。

    3. 幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。

        不可重复读和幻读读区别是,不可重复读侧重于对数据记录的修改,幻读则侧重于数据记录的新增和删除。解决不可重复读需要给满足条件的记录加锁,解决幻读则需要锁表。

 

事务隔离级别

  1. read-uncommitted(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
    2. read-committed(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
    3. repeatable-read(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生 。
      4. serializable(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,该级别可以防止脏读、不可重复读以及幻读,但是性能最差。

事务隔离级别脏读不可重复读幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

查看Mysql事务隔离级别

  使用show variables like '%tx_isolation%'或者select @@tx_isolation;语句来查看当前事务隔离级别。不过在mysql8中不支持这种方式,会提示错误,如下图

  

 

   在mysql8中就已经抛弃了这样的查询方法,https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html

  

 

   在mysql8+版本中使用select @@transaction_isolation; 或者show variables like 'transaction_isolation';就行。

    

      

 

 事务的操作和状态

  1. 开启事务:Start Transaction。

  2. 提交事务:Commit Transaction。

   3. 回滚事务:Rollback Transaction。

   4. 事务结束:End Transaction。

  TCL语句

   1. commit: 提交事务。

   2. rollback:回滚事务。

在MySQL中默认事务是自动提交的,也就是说只要执行一条DML语句就开启了事物,并且提交了事务。

 

未提交事务

  长期未提交事务,指开启事务后,长时间未向MySQL发出SQL执行请求或事务处理(COMMIT/ROLLBACK)请求,在系统表`information_schema`.`INNODB_TRX` 中状态为RUNNING,而在`information_schema`.`PROCESSLIST`中状态为SlEEP。

  导致事务长期未提交的因素很多,常见的有:

  1、事务过程中执行其他非数据库操作,导致事务长期未被处理。
  2、事务处理异常或实现逻辑有误,导致事务未被正常处理。
  3、网段异常导致应用端请求未被正常发送给数据库,数据库等待应用后续操作。
  4、应用服务器性能问题(如CPU爆满),导致应用无法及时切换到该进程进行处理。

 

与事务相关的两个日志文件

  1. 重做日志(redo log):确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。

  2. 回滚日志(undo log):保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),即非锁定读。

   

  redo log/undo log和二进制日志的区别

  1. 二进制日志是在Mysql服务层,不管是什么存储引擎,对数据库进行了修改都会产生二进制日志。而redo log/undo log是innodb层产生的,只记录该存储引擎中表的修改。并且二进制日志先于redo log/undo log被记录。
  2. 二进制日志记录操作的方法是逻辑性的语句。即便它是基于行格式的记录方式,其本质也还是逻辑的SQL设置,如该行记录的每列的值是多少。而redo log是在物理格式上的日志,它记录的是数据库中每个页的修改。
  3. 二进制日志只在每次事务提交的时候一次性写入缓存中的日志"文件"(对于非事务表的操作,则是每次执行语句成功后就直接写入)。而redo log在数据准备修改前写入缓存中的redo log中,然后才对缓存中的数据执行修改操作;而且保证在发出事务提交指令时,先向缓存中的redo log/undo log写入日志,写入完成后才执行提交动作。

不可重复读

  如果事务A 按一定条件搜索, 期间事务B 删除了符合条件的某一条数据,导致事务A 再次读取时数据少了一条。这种情况归为不可重复读。

 

可重复读和幻读(phantom read)

  在可重复读中,该sql第一次读取到数据后,就将这些数据加锁(悲观锁),其它事务无法修改这些数据,就可以实现可重复读了。但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,比如select 查询某记录是否存在,如果不存在就准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时这里就发生了幻读,而幻读不能通过行锁来避免。需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。

  但是MySQL、ORACLE、PostgreSQL等成熟的数据库,出于性能考虑,都是使用了以乐观锁为理论基础的MVCC(多版本并发控制)来实现。

 

Innodb如何解决幻读

   理论模型上的可重复读是存在幻读问题的,但是InnoDB引擎中的 可重复读级别 额外使用Next-Key锁 解决了幻读。

  MySQL 5.5 版本以后,information_schema(ski:mə) 库中新增了三个关于锁的表,亦即 innodb_trx 、innodb_locks 和 innodb_lock_waits 。其中 innodb_trx 表记录当前运行的所有事务,innodb_locks 表记录当前出现的锁,innodb_lock_waits 表记录锁等待的对应关系。

下面对 innodb_trx 表的每个字段进行解释:

trx_id:事务ID。
trx_state:事务状态,有以下几种状态:RUNNING、LOCK WAIT、ROLLING BACK 和 COMMITTING。
trx_started:事务开始时间。
trx_requested_lock_id:事务当前正在等待锁的标识,可以和 INNODB_LOCKS 表 JOIN 以得到更多详细信息。
trx_wait_started:事务开始等待的时间。
trx_weight:事务的权重。
trx_mysql_thread_id:事务线程 ID,可以和 PROCESSLIST 表 JOIN。
trx_query:事务正在执行的 SQL 语句。
trx_operation_state:事务当前操作状态。
trx_tables_in_use:当前事务执行的 SQL 中使用的表的个数。
trx_tables_locked:当前执行 SQL 的行锁数量。
trx_lock_structs:事务保留的锁数量。
trx_lock_memory_bytes:事务锁住的内存大小,单位为 BYTES。
trx_rows_locked:事务锁住的记录数。包含标记为 DELETED,并且已经保存到磁盘但对事务不可见的行。
trx_rows_modified:事务更改的行数。
trx_concurrency_tickets:事务并发票数。
trx_isolation_level:当前事务的隔离级别。
trx_unique_checks:是否打开唯一性检查的标识。
trx_foreign_key_checks:是否打开外键检查的标识。
trx_last_foreign_key_error:最后一次的外键错误信息。
trx_adaptive_hash_latched:自适应散列索引是否被当前事务锁住的标识。
trx_adaptive_hash_timeout:是否立刻放弃为自适应散列索引搜索 LATCH 的标识。

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2018-08-16 16:54  songguojun  阅读(211)  评论(0编辑  收藏  举报