一, 前言
只有 InnoDB 引擎支持事务, 下边的内容均以 InnoDB 引擎为默认条件
二, 常见的并发问题
1, 脏读
一个事务读取了另一个事务未提交的数据
2, 不可重复读
一个事务对同一数据的读取结果前后不一致. 两次读取中间被其他事务修改了
3, 幻读
幻读是指事务读取某个范围的数据时, 因为其他事务的操作导致前后两次读取的结果不一致. 幻读和不可重复读的区别在于, 不可重复读是针对确定的某一行数据而言, 而幻读是针对不确定的多行数据. 因而幻读通常出现在带有查询条件的范围查询中
三, 事务隔离级别
1, 读未提交 (READ UNCOMMITTED)
可能产生脏读, 不可重复读, 幻读
2, 读已提交 (READ COMMITTED)
避免了脏读, 可能产生不可重复读, 幻读
3, 可重复读 (REPEATABLE READ)(MySQL 默认隔离级别)
避免了脏读, 不可重复读. 通过区间锁技术避免了幻读
4, 串行化 (SERIALIZABLE)
串行化可以避免所有可能出现的并发异常, 但是会极大的降低系统的并发处理能力
四, 数据库日志有哪些?
1,undo 日志
undo 日志用于存放数据修改被修改前的值
UNDO LOG 中分为两种类型, 一种是 INSERT_UNDO(INSERT 操作), 记录插入的唯一键值;
一种是 UPDATE_UNDO(包含 UPDATE 及 DELETE 操作), 记录修改的唯一键值以及 old column 记录.
2,redo 日志
MySQL 会将一个事务中的所有 sq 先 l 记录到 redo log 中, 然后再将记录从 redo log 同步到数据文件中
它可以带来这些好处:
当 buffer pool 中的 dirty page 还没有刷新到磁盘的时候, 发生 crash, 启动服务后, 可通过 redo log 找到需要重新刷新到磁盘文件的记录;
buffer pool 中的数据直接 flush 到 disk file, 是一个随机 IO, 效率较差, 而把 buffer pool 中的数据记录到 redo log, 是一个顺序 IO, 可以提高事务提交的速度;
3,binlog 日志
用于数据库主从复制的记录, 是二进制格式. 在事务提交之后进行一个磁盘写入.
这里注意下 redo log 跟 binary log 的区别, redo log 是存储引擎层产生的, 而 binary log 是数据库层产生的. 假设一个大事务, 对 tba 做 10 万行的记录插入, 在这个过程中, 一直不断的往 redo log 顺序记录, 而 binary log 不会记录, 直到这个事务提交, 才会一次写入到 binary log 文件中
五, 数据库事务控制
1, 默认情况下, 开启事务自动提交功能. 每执行一个 sql, 都会对应一个事务的提交
2,spring 会将底层连接的自动提交特性设置为 false. 使用手动提交
六, 事务的 ACID 特性
1, 原子性 (Atomicity)
事务中的所有操作作为一个整体像原子一样不可分割, 要么全部成功, 要么全部失败.
2, 一致性 (Consistency)
事务的执行结果必须使数据库从一个一致性状态到另一个一致性状态. 一致性状态是指: 1. 系统的状态满足数据的完整性约束 (主码, 参照完整性, check 约束等) 2. 系统的状态反应数据库本应描述的现实世界的真实状态, 比如转账前后两个账户的金额总和应该保持不变.
3, 隔离性 (Isolation)
并发执行的事务不会相互影响, 其对数据库的影响和它们串行执行时一样. 比如多个用户同时往一个账户转账, 最后账户的结果应该和他们按先后次序转账的结果一样.
4, 持久性 (Durability)
事务一旦提交, 其对数据库的更新就是持久的. 任何事务或系统故障都不会导致数据丢失.
5,redo log 和 undo log 实现了原子性, 一致性, 持久性
6, 锁机制实现了隔离性
6.1, 快照读
读取的是快照版本, 也就是历史版本. 普通的 SELECT 就是快照读
6.2, 当前读
读取的是最新版本. UPDATE,DELETE,INSERT,SELECT ... ?LOCK IN SHARE MODE,SELECT ... FOR UPDATE 是当前读.
6.3, 锁定读
在一个事务中, 标准的 SELECT 语句是不会加锁, 但是有两种情况例外. SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE.
SELECT ... LOCK IN SHARE MODE
给记录假设共享锁, 这样一来的话, 其它事务只能读不能修改, 直到当前事务提交
SELECT ... FOR UPDATE
给索引记录加锁, 这种情况下跟 UPDATE 的加锁情况是一样的
6.4, 一致性非锁定读
consistent read(一致性读),InnoDB 用多版本来提供查询数据库在某个时间点的快照. 如果隔离级别是 REPEATABLE READ, 那么在同一个事务中的所有一致性读都读的是事务中第一个这样的读读到的快照; 如果是 READ COMMITTED, 那么一个事务中的每一个一致性读都会读到它自己刷新的快照版本. Consistent read(一致性读) 是 READ COMMITTED 和 REPEATABLE READ 隔离级别下普通 SELECT 语句默认的模式. 一致性读不会给它所访问的表加任何形式的锁, 因此其它事务可以同时并发的修改它们.
来源: http://www.bubuko.com/infodetail-3163186.html