mysql 事务嵌套

MySQL版本:5.7.30

简介:

        有个同事在一个事务中调用了一个存储过程,然后在回滚的时候发现,事务中的部分数据已经提交了,帮同事分析过程可以使用一个简单例子来进行表述。

创建一张表:

CREATE TABLE `test1` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `col` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

查看数据库自动提交是否已开启:

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.02 sec)

自动提交已开启。

写入两条数据:

mysql> insert into test1(col) values(1),(2);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

测试事务:

mysql> select * from test1;

+----+-----+

| id | col |

+----+-----+

| 1 | 1 |

| 2 | 2 |

+----+-----+

2 rows in set (0.03 sec)

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

mysql> update test1 set col = 3 where id = 1;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from test1;

+----+-----+

| id | col |

+----+-----+

| 1 | 3 |

| 2 | 2 |

+----+-----+

2 rows in set (0.04 sec)

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

mysql> update test1 set col = 4 where id = 2;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from test1;

+----+-----+

| id | col |

+----+-----+

| 1 | 3 |

| 2 | 4 |

+----+-----+

2 rows in set (0.04 sec)

mysql> rollback;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;

+----+-----+

| id | col |

+----+-----+

| 1 | 3 |

| 2 | 2 |

+----+-----+

2 rows in set (0.05 sec)

以上过程可以发现,在事务内部嵌套的事务开始之前的update生效了,导致外层事务后面的rollback没有实现完全回滚到事务初始状态。

参考官方文档:MySQL :: MySQL 5.7 Reference Manual :: 13.3.3 Statements That Cause an Implicit Commit

Transactions cannot be nested. This is a consequence of the implicit commit performed for any current transaction when you issue a START TRANSACTION statement or one of its synonyms.

事务不能嵌套,当嵌套的事务发出start transaction指令时,当前事务已执行的部分会进行一次隐式提交,所以以下语句已经commit了:

update test1 set col = 3 where id = 1;

后续的rollback操作当然不会回滚该已经提交的部分。

突然想到,是否可以利用这个特性来干预事务,将事务内部分成几个部分,通过不同的条件让事务实现不同程度的commit?

其实,还有一个现成的方法可以使用,通过savepoint来对事务进行干预。

以下为测试过程:

mysql> select * from test1;

+----+-----+

| id | col |

+----+-----+

| 1 | 1 |

| 2 | 2 |

+----+-----+

2 rows in set (0.06 sec)

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

mysql> update test1 set col = 3 where id = 1;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1 Changed: 1 Warnings: 0

mysql> savepoint sp1;

Query OK, 0 rows affected (0.00 sec)

mysql> update test1 set col = 4 where id = 2;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from test1;

+----+-----+

| id | col |

+----+-----+

| 1 | 3 |

| 2 | 4 |

+----+-----+

2 rows in set (0.05 sec)

mysql> rollback to savepoint sp1;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;

+----+-----+

| id | col |

+----+-----+

| 1 | 3 |

| 2 | 2 |

+----+-----+

2 rows in set (0.06 sec)

以上测试的效果同前面的事务嵌套的效果相同,可见,的确可以通过savepoint来对事务进行控制,可以让事务实现部分提交的效果。

小结:

1. 事务不能嵌套;

2. 可以通过savepoint对事务实现部分提交的效果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FightingFreedom

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值