一, 事务特性
1. 原子性
事务是一个原子操作单元, 事务中包含的所有操作要么都做, 要么都不做, 没有第三种情况.
2. 一致性
事务操作前和操作后都必须满足业务规则约束, 比如说 A 向 B 转账, 转账前和转账后 AB 两个账户的总金额必须是一致的.
3. 隔离性
隔离性是数据库允许多个并发事务同时对数据进行读写的能力, 隔离性可以防止事务并发执行时由于交叉执行导致数据不一致的问题.
4. 持久性
事务完成后, 对数据的修改是永久的, 即使出现系统故障也不会丢失.
二, 并发问题
1. 更新丢失
当两个事务选择同一行, 然后更新数据, 由于每个事务都不知道其他事务的存在, 就会发生丢失更新的问题,(你我同时读取同一行数据, 进行修改, 你 commit 之后我也 commit, 那么我的结果将会覆盖掉你的结果).
2. 脏读
一个事务正在对一条记录做修改, 在这个事务提交之前, 别的事务读取到了这个事务修改之后的数据, 也就是说, 一个事务读取到了其他事务还没有提交的数据, 就叫做脏读.
3. 不可重复读
一个事务读某条数据读两遍, 读到的是不一样的数据, 也就是说, 一个事务在进行中读取到了其他事务对旧数据的修改结果,(比如说 我开一个事务 修改某条数据 先查后改 执行修改动作的时候发现这条数据已经被别的事务删掉了)
4. 幻读
一个事务中, 读取到了其他事务新增的数据, 仿佛出现了幻象.(幻读与不可重复读类似, 不可重复读是读到了其他事务 update/delete 的结果, 幻读是读到了其他事务 insert 的结果)
三, 隔离级别
1. 未提交读 (read-uncommitted)
在一个事务中, 可以读取到其他事务未提交的数据变化, 这种读取其他会话还没提交的事务, 叫做脏读现象, 在生产环境中切勿使用.
2. 已提交读 (read-committed)
在一个事务中, 可以读取到其他事务已经提交的数据变化, 这种读取也就叫做不可重复读, 因为两次同样的查询可能会得到不一样的结果.
3. 可重复读 (repetable-read)
MySQL 默认隔离级别, 在一个事务中, 直到事务结束前, 都可以反复读取到事务刚开始时看到的数据, 并一直不会发生变化, 避免了脏读, 不可重复读现象, 但是它还是无法解决幻读问题.
4. 可串行化 (serializable)
这是最高的隔离级别, 它强制事务串行执行, 避免了前面说的幻读现象, 简单来说, 它会在读取的每一行数据上都加锁, 所以可能会导致大量的超时和锁争用问题.
5. 隔离级别一览表
隔离级别 | 读数据一致性 | 脏读 | 不可重复读 | 幻读 |
未提交读 | 最低级别,只保证不读取物理上损坏的数据 | 有 | 有 | 有 |
已提交读 | 语句级 | 无 | 有 | 有 |
可重复读 | 事务级 | 无 | 无 | 有 |
可串行化 | 最高级别,事务级 | 无 | 无 | 无 |
隔离级别越严格, 内部工作机制越复杂, 较松散的隔离级别通常可以支持更高的并发.
四, 个人分享
1. 凡是涉及到表结构的语句, 皆不受事务控制, 严格的说, 凡是 DDL 语句, 都是自带 commit. 比如 create table ,alter table,truncate 等等
2. 如果要确定出现了哪种并发问题, 先查一下当前数据库的隔离级别是什么, 再进行判断.
-- 查看当前数据库的隔离级别
SHOW VARIABLES LIKE "%tx_isolation%"
来源: http://www.linuxidc.com/Linux/2018-11/155273.htm