事务隔离:为什么你改了我还看不见?

MySQL 是一个支持多引擎的系统,但并不是所有的引擎都支持事务。比如 MySQL 原生的 MyISAM 引擎就不支持事务。

3.1事务的隔离性和隔离级别

四种隔离级别

  • 读未提交,指事务还没有提交就能被其它事务给读取到
  • 读已提交,指事务提交了才能被其它事务读取到
  • 可重复读,指在事务中多次读取的结果都是一样的
  • 串行化,指在事务中读取或更新的记录会上锁,防止其它事务读取或更新

3.2隔离的底层实现原理

在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。

Oracle 数据库的默认隔离级别其实就是“读提交”

配置的方式是,将启动参数 transaction-isolation 的值设置成 READ-COMMITTED。你可以用 show variables 来查看当前的值。

show variables like 'transaction_isolation';

3.3 可重复读的应用场景

假设你在管理一个个人银行账户表。一个表存了每个月月底的余额,一个表存了账单明细。这时候你要做数据校对,也就是判断上个月的余额和当前余额的差额,是否与本月的账单明细一致。你一定希望在校对过程中,即使有用户发生了一笔新的交易,也不影响你的校对结果。

这时候使用“可重复读”隔离级别就很方便。事务启动时的视图可以认为是静态的,不受其他事务更新的影响。

3.4事务隔离的实现

在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。

事务隔离:为什么你改了我还看不见?_第1张图片

同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。

当系统里没有比这个回滚日志更早的 read-view 的时候,回滚日志才会被删除。

所以建议尽量不要使用长事务

3.5事务的启动方式

MySQL 的事务启动方式有以下几种:

  1. 显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。
  2. set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。

建议使用显式语句的方式来启动事务。

如果纠结显示语句会多一次交互的问题,可以考虑使用commit work and chain 语法。

你可以在 information_schema 库的 innodb_trx 这个表中查询长事务,比如下面这个语句,用于查找持续时间超过 60s 的事务。

select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60

你可能感兴趣的:(#,MySQL实战45讲,MYSQL,mysql)