mysql 事务的ACID特性

老子叫甜甜 提交于 2020-01-21 03:16:47

 原子性(Atomicity)

一个事务事务的操作要么全部成功,要么全部失败

一致性(Consistency)

事务开始之前和结束之后,数据库的完整性没有被破坏,写入的资料完全符合所有的预设的规则

这里一致性可能比较难理解,比方说:A转账给B用户100元,但是A只有90元,转完之后A就是-10元了,站在数据结构层是没有问题的,但是在应用层,这个就不符合预设的规则(我们要保证用户的钱>=0)

隔离性(Isolation)

数据库允许并发的事务同时对数据库读写和修改的能力,可以防止多个事务并发执行时导致数据不一致性

持久性(Durability)

事务处理结束后,对数据的修改是永久的,即便系统故障也不会丢失

 
三 事务并发带来的问题
3.1 脏读

1.事务B更新年龄18

2.事务A读取数据库信息,年龄是18

3.事务B回滚

那么这个就是脏读

3.2 不可重复读

1.事务A先读取数据,年龄为16

2.事务B跟新数据,年龄为18

3.事务B提交

4.事务A再读取数据,年龄为18

事务A连续读取两次的数据都不一样,为不可重复读

3.3 幻读

1.事务A读取年龄大于15的数据,发现有1条记录

2.事务B插入一条记录,并提交

3.事务A再读取年龄大于15的数据,发现有2条记录

事务A就好像出现了幻觉一样,一般幻读出现在范围查询

解决上面的3个问题,就要通过事务的隔离性来解决了,那么就要了解下事务的隔离级别
四 事务的隔离级别

    Read Uncommitted(未提交读) --未解决并发问题

事务未提交对其他事务也是可见的,脏读(dirty read)

    Read Committed(提交读)        --解决脏读问题

一个事务开始之后,只能看到自己提交的事务所做的修改,不可重复读(nonrepeatable
read)

    Repeatable Read (可重复读)       --解决不可重复读问题

在同一个事务中多次读取同样的数据结果是一样的,这种隔离级别未定义解决幻读的问题

    Serializable(串行化)                --解决所有问题

最高的隔离级别,通过强制事务的串行执行
五 innodb引擎对隔离级别的支持程度

对于可重复读级别,脏读,不可重复读,幻读在innodb引擎不会出现

 

 

补充:

  1、事务隔离级别为读提交时,写数据只会锁住相应的行

  2、事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。

  3、事务隔离级别为串行化时,读写数据都会锁住整张表

   4、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

   5、MYSQL MVCC实现机制参考链接:https://blog.csdn.net/whoamiyang/article/details/51901888

   6、关于next-key 锁可以参考链接:https://blog.csdn.net/bigtree_3721/article/details/73731377

 

 

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

 

三、MySQL事务隔离级别

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

 

MySQL 的默认事务隔离级别是 Repeatable Read(可重复读)。

Oracle 的默认事务隔离级别是 Read Committed(读已提交)。

这是一个比较“怪”的现象。毕竟这两个事务隔离级别是差异是比较大的,而这两个数据库都是通用型的产品。

真实原因是MySQL为了规避一个数据复制场景中的缺陷,而选择 Repeatable Read 作为默认隔离级别。

 

基于 Statement 的 binlog

binary log 的主要用途

MySQL的 binary log 记录了数据库的“事件”。这些“事件”描述了数据库的改动,包括 表的创建、数据修改等。

 

binary log 主要用于:

  • 主从复制。主库 master 会将其 binary log 中的数据改动记录(“事件”)发送给 从库 slave。从库执行这些“事件”使数据与主库保持一致。
  • 数据恢复

 

binary log 的三种模式

binary log 有三种模式:

  • Statement:记录的是可能改变数据的SQL语句
  • Row:记录的是每行数据的变更
  • 混合模式:
    默认使用 Statement 格式的记录;
    当遇到可能引起 “基于Statement的数据复制问题” 时自动转换为 Row 模式。

 

基于Statement的数据复制问题


 

上述两个事务的隔离级别都是 Read-Committed。

真实的执行顺序是 先删后插。而 binlog 中记录的 Statement 顺序为 先插后删

当基于这份 Statement 格式的 binlog 进行主从复制或恢复数据时,得到的最终数据与实际情况不符。

 

两种解决方法:

  • 选用 Row 模式 的 binlog
    针对实际数据行的记录当然可以准确反映改动历史
  • 选用 Repeatable-Read 事务隔离级别
    “可重复读”隔离级别下,delete、insert 等语句会对数据加 间隙锁。上述Session2中的insert语句将被阻塞,直到session1 commit;

因为早期MySQL只支持 Statement 格式的 binlog,所以只能采用 Repeatable-Read 隔离级别来规避数据不一致的风险。

从 5.7.7 开始,MySQL的默认 binlog 格式已经是 ROW

 

选哪种事务隔离级别?

大多数项目中可以选 Read-Committed(读已提交),既降低死锁几率,又能提升并发性能。同时选用 Row 模式的binlog。

 

当然,这类 “最终一致性”的事务解决方案可能无法满足某些特殊项目的需求,需要采用 Serializable (串行)的隔离级别。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!