事务
事务就是一组原子性的SQL查询,或者说一个独立的工作单元。如果数据库引擎能够成功地对数据库应用该组查询的全部语句,那么就执行该组查询。如果其中有任何一条语句因为崩溃或其他原因无法执行,那么所有的语句都不会执行。也就是说,事务内的语句,要么全部执行成功,要么全部执行失败。
ACID
- atomicity(原子性) :要么全执行,要么全都不执行;
- consistency(一致性):在事务开始和完成时,数据都必须保持一致状态;
- isolation(隔离性) :事务处理过程中的中间状态对外部是不可见的;
- durability(持久性) :事务完成之后,它对于数据的修改是永久性的。
InnoDB 采用 redo log 机制来保证事务更新的一致性和持久性。
Redo log
Redo log称为重做日志,用于记录事务操作变化,记录的是数据被修改之后的值。
Redo log 由两部分组成:
- 内存中的重做日志缓冲(redo log buffer)
- 重做日志文件(redo log file)
每次数据更新会先更新 redo log buffer,然后根据 innodb_flush_log_at_trx_commit 来控制 redo log buffer 更新到redo log file 的时机。innodb_flush_log_at_trx_commit 有三个值可选:
- 0:事务提交时,在事务提交时,每秒触发一次 redo log buffer 写磁盘操作,并调用操作系统 fsync 刷新 IO 缓存。
- 1:事务提交时,InnoDB 立即将缓存中的 redo 日志写到日志文件中,并调用操作系统 fsync 刷新 IO 缓存;
- 2:事务提交时,InnoDB 立即将缓存中的 redo 日志写到日志文件中,但不是马上调用 fsync 刷新 IO 缓存,而是每秒只做一次磁盘 IO 缓存刷新操作。
innodb_flush_log_at_trx_commit 参数的默认值是 1,
Binlog
二进制日志(binlog)记录了所有的 DDL(数据定义语句)和 DML(数据操纵语句)
Binlog 有以下几个作用:
- 恢复:数据恢复时可以使用二进制日志
- 复制:通过传输二进制日志到从库,然后进行恢复,以实现主从同步
- 审计:可以通过二进制日志进行审计数据的变更操作
sync_binlog 来控制累积多少个事务后才将二进制日志 fsync 到磁盘。
- sync_binlog=0,表示每次提交事务都只write,不fsync
- sync_binlog=1,表示每次提交事务都会执行fsync
- sync_binlog=N(N>1),表示每次提交事务都write,累积N个事务后才fsync
数据库突然断电不丢数据
只要 innodb_flush_log_at_trx_commit 和 sync_binlog 都为 1(通常称为:双一),就能确保MySQL 机器断电重启后,数据不丢失。
事务建议
- 循环写入的情况,如果循环次数不是太多,建议在循环前开启一个事务,循环结束后统一提交。
- 优化事务里的语句顺序,减少锁时间。
- 关注不同事务访问资源的顺序,避免死锁。
- 创建事务之前,关注事务隔离级别。
- 不在事务中混合使用存储引擎(MyISAM无法回滚)
分布式事务
分布式事务使用两阶段提交协议:
第一阶段:所有分支事务都开始准备,告诉事务管理器自己已经准备好了;
第二阶段:确定是 rollback 还是 commit,如果有一个节点不能提交,则所有节点都要回滚。
MySQL 自带的分布式事务
xa start 'a','a_1'; //启动分支事务
xa end 'a','a_1'; //结束分支事务
xa prepare 'a','a_1'; //进入准备状态
xa commit 'a','a_1'; //提交分支事务
xa recover; //返回当前数据库中处于 prepare 状态的分支事务的详细信息