什么是事物
事务 (Transaction)是由一系列对数据库中的数据进行操作访问所组成的一个程序执行单元
在同一个事务中所进行的操作,要么都成功,要么就什么都不做。理想中的事务必须满足四大特性,这就是大名鼎鼎的ACID。
mysql 事务四大特性(ACID)
A(Atomicity)-原子性
是指一个事务要么全部执行,要么不执行,也就是说一个事务不可能只执行了一半就停止了。
比如 A 账户 向B账户转账 A 减 100 元 B 必须增加 100 元 试想,如果第一步成功了,那么第二步失败了,那就等于A的100元钱直接消失了,相信这是任何人都不能接受的事项,所以数据库事务才需要保证原子性。
C (Consistent)-一致性
指的是在事务开始之前和事务结束之后,数据库的完整性约束都没有被破坏,事务执行的前后都是合法的数据状态。
例如,完整性约束了a+b=10,一个事务改变了a,那么b也应该随之改变
I(Isolation)-隔离性
隔离性就是说每个事务之间的操作应该相互隔离,互不干扰。比如说一个事务提交之前对另一个事务不可见。
隔离是一个相对抽象而复杂的概念,比如说事务之间的隔离性我们到底要隔离到哪种程度呢?所以,针对隔离,SQL92标准定义了4种隔离级别,这个放在后面事务的隔离级别中介绍。
D(Durable)-持久性
事务一旦完成数据就会永久性的保存在数据库 不会随之丢失
mysql 开启事事务
查看事物是否提交
SHOW VARIABLES LIKE 'autocommit'
select @@autocommit
开启关闭事物
SET autocommit = 'OFF'
SET @@autocommit = 0
不过需要注意的是,这种修改方式只是在当前会话窗口生效,对其他会话窗口是不生效的,MySQL几乎所有变量设置都会分成两个级别,session(会话)和global(全局)级别,默认就是session级别。
常用的事务控制语句
START TRANSACTION或者BEGIN:显示的开启事务。需要注意的是在存储过程中只能用START TRANSACTION开启事务,因为存储过程本来有BEGIN…END语法,两者会冲突。
COMMIT:提交事务。也可以写成COMMIT WORK。
ROLLBACK:回滚事务。也可以写成ROLLBACK WORK。
事务并发会导致的问题
脏读
事务A 提交一条数据但是未commit数据 这时候事务B读取到了事物A未提交的脏数据,造成了脏读。-一个事务读取到另一个事务未提交的数据
不可重复读
事务A 第一次读取到了数据A=1 -> 事务B对数据A进行了更改 A=2并提交 -> 事务A 第二次读取到的数据A=2 造成两次读取到的数据不一致 不可重复读
- 幻读
事物A 第一次通过条件查询 出一批数据 A = 1 B = 2 此时 -> 事务B 提交了一条数据C =3(或删除了一条) -> 事务A 再次通过条件查询 多了一条数据 C = 3(或者少了一条数据) 造成了幻读
幻读和不可重复读很容易造成记忆混乱 幻读主要是针对新增删除 造成其他事务 多读或者少读了数据 不可重复读主要是对同一条数据前后读取到了不同的内容 重复读数据不一致
解决事务问题mysql 提供的四种事物隔离级别
SQL 标准定义了四种隔离级别,MySQL 全都支持。这四种隔离级别分别是:
读未提交
可以读取到其他事未提交的数据 这样会造成 脏读 不可重复读 幻读 一般不推荐使用 最低的隔离级别
读已提交
只能读取到其他事务已经提交的数据,这样可以避免脏读 但是任然会造成不可重复读和幻读 大多数数据使用的这个隔离级别 但是mysql不是
可重复读
mysql默认的隔离级别 保证了同一个事务多次读取 结果都是一样的 可以避免 脏读 和不可重复读 但是任然不能避免 幻读 (InnoDB引擎例外,InnoDB引擎通过间隙锁解决了幻读问题)。
串行化
最高的隔离级别 对事务来说相当于按顺序同步执行 效率来说是最低的 他会在读取的时候给每一个行加锁,所以可能导致大量的超时和锁争用的情况,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下才考虑的级别。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read uncommitted) | 可能 | 可能 | 可能 |
读已提交(READ-COMMITTED) | 不可能 | 可能 | 可能 |
可重复读 (REPEATABLE-READ) | 不可能 | 不可能 | 可能 |
可串行化 (SERIALIZABLE) | 不可能 | 不可能 | 不可能 |
mysql通过 MVCC 来实现的事务隔离级别
MVCC,多版本的并发控制,英文全称:Multi Version Concurrency Control。就是当我们在修改数据的时候,可以为这条数据创建一个快照,后面就可以直接读取这个快照。
在聚簇索引中每条数据存在两条隐藏列 一个是事务id 一个是回滚指针 回滚指针对应着undolog中的回滚日志 在 undolog中有一条回滚数据的回滚链数据回滚就是靠这个来实现的
读已提交的实现机制和可重复的的区别是读取视图的方式不一致
事物 A 插入数据
name | age | trn_id | roll_point |
---|---|---|---|
张三 | 1 | 1 | null |
事物B 读取数据
name | age | trn_id | roll_point |
---|---|---|---|
张三 | 1 | 2 | null |