事务
事务保证一组数据库操作要么全成功,要么全失败,mysql中事务在存储引擎层实现
事务包含四个特性:ACID( 即原子性、一致性、隔离性、持久性)
事务隔离级别
当数据库中多个事务同时执行可能出现脏读、不可重复读、幻读,而隔离级别的概念就是用于解决上述问题
事务隔离级别包括: 读未提交、读提交、可重复读、串行化,隔离程度依次增强,效率依次降低,在mysql中通过show variables like 'transaction_isolation'
查看当前引擎隔离级别
读未提交
即事务没提交前做的变更,就能被其它事务看到,也就是说直接返回记录上的最新值,无视图概念
读已提交
即事务做的变更提交后才能被其它事务看到,也就是说在每个sql语句开始执行时创建视图,Oracle默认隔离级别读已提交
可重复度
相比读已提交,事务执行期间看到的数据前后一致,也就是说在事务启动时创建视图,mysql默认隔离级别为可重复度
可串行化
即对同一行记录通过添加读写锁的方式避免并行访问
实现原理
因为事务的操作要么全成功,要么全失败。失败后通过回滚日志来恢复原值
在mysql中每条记录更新时都会同时记录回滚操作, 由于记录可以存在多个版本( MVCC,也就是数据库的多版本并发控制),因此不同时刻启动的事务可能有不同的read-view,他们回滚到的位置也不同
当事务提交前,它可能用到的回滚记录都必须保留。
一个事务操作越多(长事务),链表就越长,占用内存越多。除此之外长事务还占用锁资源,因此尽量避免使用长事务
启动事务方式
- 通过begin 或 start transaction显式启动事务,提交 commit,回滚 rollback
- 通过
set autocommit=0
关掉自动提交,这个事务持续存在直到执行 commit 或 rollback 语句或断开连接
避免长事务
从应用开发端看:
- 建议通过
set autocommit=1
打开自动提交,单独对事务显示启动。对于频繁使用事务的业务,为了减少一次交互可采用commit work and chain
(即提交并再次开启事务,由begin…commit;begin…commit变为begin…commit work and chain…commit) - 确认是否有不必要的只读事务(对于多个select语句的只读事务可以去掉)
- 根据业务本身的预估,通过
SET MAX_EXECUTION_TIME
来控制每个语句执行的最长时间,避免单个语句意外执行太长时间
从数据库端看
- 监控
information_schema.Innodb_trx
表,设置长事务阈值,超过就报警或kill,比如通过select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60
来查找时间超过60s的事务 - 推荐使用Percona 的 pt-kill 工具
- 在业务功能测试阶段要求输出所有的 general_log,分析日志行为提前发现问题
- 将
innodb_undo_tablespaces
设置成2或更大值(如果真出现回滚段过大,这样设置后清理起来更方便)