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

Posted 2021-04-17 15:00 +0800 by ZhangJie ‐ 1 min read

分享:  

数据库事务(刚性事务)

事务特性:ACID

  • Atomic
  • Consistency
  • Isolation
  • Durability

事务隔离性及事务隔离级别:

  • read uncommited
  • read committed
  • repeatable read
  • serializable

在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。

  • 在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。
  • 在“读提交”隔离级别下,这个视图是在每个SQL语句开始执行的时候创建的。
  • 这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;
  • 而“串行化”隔离级别下直接用加锁(读写冲突、写写冲突)的方式来避免并行访问。

事务隔离性级别通过变量 transaction_isolation 来设置。

MVCC:

在执行更新操作的时候,也会对应的插入一行“回滚记录”,用于MVCC(多版本并发控制)中构建不同时间启动的事务的视图,这主要是为了维持一个可重复读的视图。

比如现在执行操作假如现在c=1,执行update c=2, c=3, c=4的操作,那么对应的就会插入四行回滚记录,将2回滚为1,将3回滚为2,将4回滚为3。

三个更新操作的时刻t1、t2、t3,相当于确立了三个边界,边界时间点前后可能会有不同的事务启动、结束。那些依然还未结束的事务,通过他们的启动时间与回滚记录插入时的时间做对比,就可以找到应该依次执行哪些回滚记录来恢复到启动事务时的数据库状态,通过这种方式来重建一个可重复读的视图。

这就是MVCC的要义。

这些回滚日志,多了之后也会占用存储空间,浪费资源,需要清除?但是假如有个事务是时刻t启动的,那么时刻t之后的回滚日志都是要保留的,如果这个事务执行时间很长,就会导致回滚日志积累很多,浪费资源。因此不建议使用长事务。

查找执行时间超过60s的长事务:

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

了解下这个事务统计表几个比较有用的字段:

mysql> desc innodb_trx;
+----------------------------+-----------------+------+-----+---------+-------+
| Field                      | Type            | Null |                       |
+----------------------------+-----------------+------+-----+---------+-------+
| trx_id                     | bigint unsigned | NO   | 事务id                 |
| trx_state                  | varchar(13)     | NO   | 事务状态,如RUNNING     |
| trx_started                | datetime        | NO   | 事务启动时间            |
...
| trx_tables_locked          | bigint unsigned | NO   | 增删记录会锁表的        |
...
| trx_rows_locked            | bigint unsigned | NO   | 更新记录会锁行的        |
| trx_rows_modified          | bigint unsigned | NO   | 修改的行数量           |
...
| trx_isolation_level        | varchar(16)     | NO   | 当前事务隔离级别        |
...
+----------------------------+-----------------+------+-----+---------+-------+