zoukankan      html  css  js  c++  java
  • Mysql事务详解

    一、ACID

    1、事务及其ACID属性

    • 原子性:事务是一个原子操作单位,其对数据的修改,要么全部执行,要么全部不执行。
    • 一致性:在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到
    • 隔离性:数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
    • 持久性:事务完成之后,它对于数据的修改是永久性的。这意味着事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚、

    二、事务的并发问题

    • 脏读:一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。也就是说,读取到了未提交的数据;意味着在事务A中,事务B虽然没有提交,但它任何一条数据变化,事务A都可以看到。

    • 不可重复读:一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变或某些记录已经被删除了!比如说, 在一个事务内,多次读同一个数据。在这个事务还没有结束时,另一个事务也访问该同一数据。那么,在第一个事务的两次读数据之间。由于第二个事务的修改,那么第一个事务读到的数据可能不一样,这样就发生了在一个事务内两次读到的数据是不一样的

    • 幻读:一个事务按相同的查询条件重新读取以前检索过得数据,却发现其他事务插入了满足其查询条件的新数据

    不可重复读和幻读的区别应该在于:

    不可重复读是主要是说多次读取一条记录, 发现该记录中某些列值被修改过。

    幻读是主要是说多次读取一个范围内的记录(包括直接查询所有记录结果或者做聚合统计), 发现结果不一致(标准档案一般指记录增多, 记录的减少应该也算是幻读)

    解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁住表

    三、事务的隔离机制

    (1)命令

    修改隔离级别:

    set tx_isolation='read-commited/read-uncommited/repeatable-read/serializable'
    

    查看隔离级别:

    select @@tx_isolation
    

    (2)事务隔离级别

    分为四个隔离级别:未提交读、已提交读、可重复读(MySQL默认)、可序列化

    隔离级别 读数据一致性 脏读 不可重复读 幻读
    未提交读(read-uncommitted) 最低级别,只能保证不读取物理上损坏的数据
    已提交读(read-committed) 语句级
    可重复读(repeatable-read) 事务级
    可序列化(serializable) 最高级别,事务级

    (3)隔离级别示例讲解

    查看mysql默认的事务隔离级别为repeatable-read

    未提交读

    (1)打开一个客户端A,并设置当前事务模式为read uncommitted(未提交读),查询user表的pwd字段

    (2)在客户端A事务提交之前,打开另一个客户端B,更新user表的pwd字段

    (3)这时,虽然客户端B的事务还没提交,但是客户端A就可以查询到客户端B已经更新的数据了

    (4)一旦客户端B的事务以为某种原因回滚,所有的操作都将会被撤销,那客户端A查询到的数据其实就是脏数据

    已提交读

    (1)打开一个客户端A,并设置当前事务模式为read committed(未提交读),查询表user的所有记录:

    (2)在客户端A的事务提交之前,打开另一个客户端B,更新表user:

    (3)这时,客户端B的事务还没提交,客户端A不能查询到B已经更新的数据,解决了脏读问题:

    (4)客户端B的事务提交

    (5)客户端A执行与上一步相同的查询,结果 与上一步不一致,即产生了不可重复读的问题

    可重复读

    (1)打开一个客户端A,并设置当前事务模式为repeatable read,查询表user的所有记录

    (2)在客户端A的事务提交之前,打开另一个客户端B,更新表user并提交

    (3)在客户端A查询表user的所有记录,与步骤(1)查询结果一致,没有出现不可重复读的问题

    (4)重新打开客户端B,插入一条新数据后提交

    (5)在客户端A查询表account的所有记录,没有 查出 新增数据,所以没有出现幻读 (疑惑的地方)

    可序列化

    (1)打开一个客户端A,并设置当前事务模式为serializable,查询表user的初始值:

    (2)打开一个客户端B,并设置当前事务模式为serializable,插入一条记录报错,表被锁了插入失败,mysql中事务隔离级别为serializable时会锁表,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到。

    注意事项

    • 事务隔离级别为读提交时,写数据只会锁住相应的行
    • 事务隔离级别为串行化时,读写数据都会锁住整张表
    • 隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
  • 相关阅读:
    C++小知识之Vector用法
    云计算和大数据入门
    C++解析JSON之JsonCPP
    OSS研究
    linux内核--进程地址空间(三)
    学习笔记:修改网吧计费系统
    学习笔记:找回电脑开机密码
    例说C#深拷贝与浅拷贝
    JBossESB教程(一)——开发环境的搭建
    Java集合---ConcurrentHashMap原理分析
  • 原文地址:https://www.cnblogs.com/sxkgeek/p/9585911.html
Copyright © 2011-2022 走看看