当Transactional碰到锁,有个大坑,要小心。 (2)

org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin

当Transactional碰到锁,有个大坑,要小心。

先看我下面框起来的那一行日志:

Switching JDBC Connection [HikariProxyConnection@946359486 wrapping com.mysql.jdbc.JDBC4Connection@7a24806] to manual commit

你知道的,我是个技术博主,偶尔教点单词。

Switching,转换。

Connection,链接。

manual commit,手动提交。

Switching ... to ...,把什么转换为什么。

没想到吧,这次学技术的同时不仅学了几个单词,还会了一个语法。

当Transactional碰到锁,有个大坑,要小心。

所以,上面那句话翻译过来就非常简单了:

把数据库连接切换为手动提交。

然后,我们看一下打印这行日志的代码逻辑,也就是被框起来的代码部分。

我单独拿出来:

当Transactional碰到锁,有个大坑,要小心。

逻辑非常清晰,就是把连接的 AutoCommit 参数从 ture 修改为 false。

那么现在问题就来了,这个时候,事务启动了吗?

我觉得没启动,只是就绪了而已。

启动和就绪还是有一点点差异的,就绪是启动之前的步骤。

那么事务的启动有哪些方式呢?

第一种:使用启动事务的语句,这种是显式的启动事务。比如 begin 或 start transaction 语句。与之配套的提交语句是 commit,回滚语句是 rollback。

第二种:autocommit 的值默认是 1,含义是事务的自动提交是开启的。如果我们执行 set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。

很显然,在 Spring 里面采用的是第二种方式。

而上面的代码 con.setAutoCommit(false) 只是把这个链接的自动提交关掉。

事务真正启动的时机是什么时候呢?

前面说的 begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作 InnoDB 表的语句,事务才算是真正启动。

如果你想要马上启动一个事务,可以使用 start transaction with consistent snapshot 这个命令。需要注意的是这个命令在读已提交的隔离级别(RC)下是没意义的,和直接使用 start transaction 一个效果。

回到在前面的问题:什么时候才会执行第一个 SQL 语句?

就是在 lock 代码之后。

所以,显然事务的开启一定是在 lock 之后的。

这一个简单的“显然”,先给大家铺垫一下。

接下来,给大家上给动图看一眼,更加直观。

首先说一下这个 SQL:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdfsx.html