事务隔离
MySQL原生引擎MyISAM不支持事务,所以被InnoDB取代。
事务, ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)
redis 的隔离性是?
redis 的事务中的隔离性并没有保证原子性,已经做过的操作是不会rollback的。
它的隔离性是指其他事务不会干扰到它自己的事务。
隔离性与隔离级别
隔离性Isolation:一个事务执行时不能受其他事务的干扰。
隔离级别
-
读未提交 read uncommitted
- 事务还没提交时,他做的变更能被其他事务看到
-
读已提交 read committed
- 一个事务提交之后,他做的变更才能被其他事务看到
-
可重复读 repeatable read
- 一个事务在执行过程中看到的数据与这个事务在启动时看到的数据是一样的。(别人改数据的事务已经提交,我在我的事务中也不去读)
-
串行化 serializable
- 对同一行记录,写时加“写锁”,读时加“读锁”,出现冲突时按顺序完成。(我的事务尚未提交,别人别想改数据)
-
总结
- 读未提交:别人改数据的事务尚未提交,我在我的事务中也能读到。
读已提交:别人改数据的事务已经提交,我在我的事务中才能读到。
可重复读:别人改数据的事务已经提交,我在我的事务中也不去读。
串行:我的事务尚未提交,别人就别想改数据。
这4种隔离级别,并行性能依次降低,安全性依次提高。
- 读未提交:别人改数据的事务尚未提交,我在我的事务中也能读到。
数据库对隔离级别的实现
-
DB会创建一个视图
- 可重复读:视图在事务启动时创建,整个事务存在期间都用这个视图。
- 读已提交:视图在每个SQL语句开始执行的时候创建的。
-
读未提交:直接返回记录上的最新值,没有视图概念
-
串行化:直接用加锁的方式来避免并行访问
-
Oracle默认:读已提交,MySQL中的设置:transaction-isolation设置为read-committed,用show variables来查看
-
可重复读的场景
-
数据校对逻辑的案例
- 校对上个月的余额和这个月余额的差值,你希望在校对过程中,及时有用户发生了新的交易,也不影响校对结果。
-
事务隔离的实现
在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。
同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)
事务的启动方式
1. 显式启动事务语句
- begin/start transaction、commit、rollback
2. 关闭线程的自提交
- set autocommit=0,事务会持续存在直到你主动执行commit或者rollback,或者断开连接
所以,如果采取了第二种方法,就导致了接下来的查询都在事务中,如果是长连接,就导致了长事务。
所以,建议使用set autocommit=1
长事务的查询:在information_schema库下的innodb_trx表中查询。
举个栗子
如何避免长事务对业务的影响?
-
从应用开发端来看
-
- 确定是否使用了set autocommit=0,如是,则改成1
-
- 确定是否有不必要的只读事务
-
- 业务连接数据库的时候,控制每个语句执行的最长时间 set max_execution_time
-
-
从数据库端来看
-
- 监控相关表,设置长事务阈值,超过就报警/kill
-
- 可使用percona的pt-kill工具
-
- 在功能测试阶段输出所有的log,分析日志提前发现问题
-
- 把innodb_undo_tablespaces设置成2或者更大的值
-