[MySQL事务一文搞懂]
[MySQL事务一文搞懂]
1、什么是事务?
事务(Transaction),顾名思义就是要做的或所做的事情,数据库事务指的则是作为单个逻辑工作单元执行的一系列操作(SQL语句)。这些操作要么全部执行,要么全部不执行。
2、为什么需要事务
把一系列sql放入一个事务中有两个目的:
-
为数据库操作提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
-
当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
""" 当一个事务被提交给了DBMS(数据库管理系统),则DBMS需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要被回滚,回到事务执行前的状态(要么全执行,要么全都不执行);同时,该事务对数据库或者其他事务的执行无影响,所有的事务都好像在独立的运行。 但在现实情况下,失败的风险很高。在一个数据库事务的执行过程中,有可能会遇上事务操作失败、数据库系统/操作系统失败,甚至是存储介质失败等情况。这便需要DBMS对一个执行失败的事务执行恢复操作,将其数据库状态恢复到一致状态(数据的一致性得到保证的状态)。为了实现将数据库状态恢复到一致状态的功能,DBMS通常需要维护事务日志以追踪事务中所有影响数据库数据的操作。 """
3、事务的四大特性(ACID)
ACID 即Atomicity、Consistency、Isolation、Durability的缩写
1、原子性(Atomicity)
一个事务的执行是整体性的,不可分割,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
2、一致性(Consistency)
事务应确保数据库的状态从一个一致状态转变为另一个一致状态。例如转账行为中:一个人减了50元,另 外一个人就应该加上这50元,而不能 是40元。其他一致状态的含义是数据库中的数据应满足完整性约束, 例如字段约束不能为负数,事务执行完毕后的该字段也同样不是负数
3、隔离性(Isolation)
多个事务并发执行时,一个事务的执行不应影响其他事务的执行, 且多个事务不能看到对方的中间状态(提交或者回滚之前的状态)
4、持久性(Durability)
一个事务的提交,对数据库的修改是永久保存在数据库中的,不受外部因素或其他操作影响。
4、事务的隔离级别
注意: 下方表格即代表 每个隔离级别是否存在并发事务所导致的问题!
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read uncommitted 读未提交 | √ | √ | √ |
Read committed 读已提交 | × | √ | √ |
Repeatable Read (MySQL默认隔离级别) 可重复读 | × | × | √ |
Serializable 串行化 | × | × | × |
5、并发事务导致的问题!
注意:下列问题其实就是由于并发事务可能会出现的问题(可用提高数据库隔离级别解决 下面会详解)
-
脏读(dirty read)
""" 脏读其实就是 事务A 读取到了 事务B 未提交的数据! 比如: 事务A 查询账户金额为200 在此期间 事务B 将当前账户存入100 但是并未提交事务(事务只有再提交后才生效) 接下来 事务A 又查询了当前账户金额 发现为300! 事务B 并未提交数据 而 事务A 则读取到事务B未提交后的数据! 解决: 将数据库隔离级别修改为: Read committed """
-
不可重复读(non repeatable read)
""" 不可重复读其实就是 事务A 执行相同的Sql却读取到了不同的数据! (和脏读不同的是 它读取到的是已经提交过的事务数据) 比如: 事务A 查询账户金额为 200 事务B 修改金额为300 并且提交事务 然后 事务A 又查询了账户金额发现为 300 这样就导致了 事务A 再同一次事务中执行同样的Sql而获取到不同的值! 解决: 将数据库隔离级别修改为: Repeatable Read """
-
幻读(phantom read)
""" 幻读其实就是事务A再查询某条数据发现并不存在!但是再插入数据的时候却发生ERROR说当前数据已经存在 (其实这是再不可重复读解决后发生的下一个问题) 比如: 事务A 查询 ID=3 的数据没有! 此时 事务B 启动 执行插入了 id=3的一条数据 然后 事务A 发现ID为3的数据 并没有 也插入了一条 id=3的数据后报错说 已经存在! 这是因为 我们的数据隔离级别已经是可重复的 所以事务A 每次查询到的都是最初未改变的状态! 解决: 将数据库隔离级别修改为: Serializable """