事务的实现

之前的文章说过事务隔离等级

现在说说事务等级为“可重复读”的事务怎么是实现的

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

假设一个值从 1 被按顺序改成了 2、3、4,在回滚日志里面就会有类似下面的记录。

 

mysql 从哪个文件启动_MySQL

 

  上图中 进行了ABC 三个事务 把初始值1改变了3次变成了4,每次事务都会有他自己的read-view和回滚日志, 对于read-view A来说他要像得到1,就要把4依次执行三次回滚操作来得到

  每个事务都会有回滚日志,这样会有很多的回滚日志,占用资源。所以回滚日志会在不需要的时候才删除。也就是说,系统会判断,当没有事务再需要用到这些回滚日志时,回滚日志会被删除。就是当系统里没有比这个回滚日志更早的 read-view 的时候。   

   因为上面的原因所以最好不要用长事务,长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。而且长事务还占用锁资源,也可能拖垮整个库

你可以在mysql中用下面的语句查找持续时间超过 60s 的事务,然后进行对长事务进行优化。

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

 

事务的启动方式

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

1.显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。

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

有些客户端连接框架会默认连接成功后先执行一个 set autocommit=0 的命令。这就导致接下来的查询都在事务中,如果是长连接,就导致了意外的长事务。因此,我会建议你总是使用 set autocommit=1, 通过显式语句的方式来启动事务。

SELECT @@autocommit;

可以查看MySQLautocommit的值默认是1;

tp3.2.3 中开启事务的时候会把这个值改为0.然后再提交和回滚后再把值改回1。

mysql 从哪个文件启动_mysql 从哪个文件启动_02

mysql 从哪个文件启动_回滚_03

  但是使用set autocommit=1的时候会有一个问题,在一个需要频繁使用事务的业务中,每次事务开始都要begin,会增加交互次数,对于这个问题可以使用 commit work and chain 语法,这个操作就是begin显式启动时候后不用commit来提交事务而是用commit work and chain,这个就是提交事务并且开启下一个事务。这样就解决了多次begin的问题,同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中。