内容简介:手册地址默认的, 如果不修改mysql配置文件, 会启用 自动提交功能auto commit, 即隐式提交你的每一条SQL语句;有些语句,在执行之前,会隐式地发出commit。这些语句包括:
手册地址 https://dev.mysql.com/doc/refman/8.0/en/savepoint.html
默认的, 如果不修改 mysql 配置文件, 会启用 自动提交功能auto commit, 即隐式提交你的每一条 SQL 语句;
有些语句,在执行之前,会隐式地发出commit。这些语句包括:
- DDL语句, 比如 create database/drop database, create/drop/alter table/routine
- 隐式地使用或者修改mysql数据库的语句,比如 ALTER USER, CREATE USER, DROP USER, GRANT, RENAME USER, REVOKE, SET PASSWORD
- 事务控制和锁语句,比如BEGIN,START TRANSACTION, LOCK/UNLOCK TABLES, SET autocommit = 1(原来不是1)
- LOAD数据语句, LOAD DATA INFILE
- 管理语句,比如 ANALYZE TABLE, CACHE INDEX, CHECK TABLE等等
- 复制控制语句,比如 START/STOP/RESET SLAVE, CHANGE MASTER TO
示例:
mysql> set autocommit=1; mysql> BEGIN; mysql> CREATE TABLE T2(ID INT); mysql> INSERT INTO T2 VALUES(100); mysql> ROLLBACK; mysql> SELECT * FROM T2; +------+ | ID | +------+ | 100 | +------+ 1 row in set (0.00 sec) ————————————————
事务的基础操作:
开启事务(进入事务模式,不会自动提交) START TRANSACTION; 或者简写 BEGIN;
提交事务 COMMIT;
回滚事务 ROLLBACK;
关闭提交之后, 无需开启事务, 等价于"已经在事务模式下", 需要手动COMMIT或ROLLBACK才能使SQL发生作用;
当前TCP session级别, 关闭自动提交 SET autocommit=0;
全局, 关闭自动提交 SET GLOBAL autocommit=0;
重要提示:DDL语句无法被回滚, 上面说了"有些语句会提供commit提交",比如 create database/drop database, create/drop/alter table/routine。
在需要COMMIT/ROLLBACK的场景下, 可以阶段性的回滚和提交, 即 "打点计时器" 一样, 留下锚点(保存点, save point);
-
开启事务后,在事务内声明存档点 SAVEPOINT $name
批处理也是事务, 比如: (1)BEGIN;(2)巴拉巴拉多条SQL;;(3)COMMIT;或ROLLBACK;
-
提交事务之前,释放存档点 RELEASE SAVEPOINT $name
只会移除这一个存档点,不影响其他存档点, 也不会自动触发commit或rollback; 如果释放的存档点不存在,则报错 ERROR 1305 (42000): SAVEPOINT identifier does not exist
-
回滚至某个存档点 ROLLBACK TO SAVEPOINT $name
如果回滚的存档点不存在,则报错 ERROR 1305 (42000): SAVEPOINT identifier does not exist
- 执行COMMIT或ROLLBACK后, 自动删除 事务内的所有存档点;
-
开启事务之前, 可以设置隔离级别:
SET TRANSACTION ISOLATION LEVEL $level;
四种级别情况,
第一种情况:
READ COMMITTED
作用是:
指定在读取数据时控制共享锁以避免脏读,但数据可在事务结束前更改,从而产生不可重复读取或幻像数据。该选项是 SQL Server的默认值。
第二种情况:
READ UNCOMMITTED
作用是:
执行脏读或0级隔离锁定,这表示不发出共享锁,也不接受排它锁。当设置该选项时,可以对数据执行未提交读或脏读;在事务结束前可以更改数据内的数值,行也可以出现在数据集中或从数据集消失。该选项的作用与在事务内所有语句中的所有表上设置 NOLOCK 相同。这是四个隔离级别中限制最小的级别。
第三种情况:
REPEATABLE READ
作用是:
锁定查询中使用的所有数据以防止其他用户更新数据,但是其他用户可以将新的幻像行插入数据集,且幻像行包括在当前事务的后续读取中。因为并发低于默认隔离级别,所以应只在必要时才使用该选项。
第四种情况:
SERIALIZABLE
作用是:
在数据集上放置一个范围锁,以防止其他用户在事务完成之前更新数据集或将行插入数据集内。这是四个隔离级别中限制最大的级别。因为并发级别较低,所以应只在必要时才使用该选项。该选项的作用与在事务内所有 SELECT 语句中的所有表上设置 HOLDLOCK相同。
SAVEPOINT语法如下: SAVEPOINT identifier ROLLBACK [WORK] TO [SAVEPOINT] identifier RELEASE SAVEPOINT identifier
注意: 如果存档点的名称(标识符identifier)跟上方重复了, 则删除旧的存档点, 设置新的存档点, 相当于"游戏存档"被擦写覆盖了。
示例:
mysql> CREATE TABLE T2(ID INT); mysql> BEGIN; mysql> INSERT INTO T2 VALUES(100); mysql> SAVEPOINT sp1; mysql> INSERT INTO T2 VALUES(200); mysql> ROLLBACK TO SAVEPOINT sp1; mysql> RELEASE SAVEPOINT sp1; mysql> COMMIT; mysql> SELECT * FROM T2; +------+ | ID | +------+ | 100 | +------+ 1 row in set (0.00 sec) ————————————————
存档点可以层叠嵌套, 很像"操作系统在切换进程上下文的时候,压栈/弹栈", 具体表现在:
- 当 "调用invoke"存储过程/函数(store function) 或 激活(activated)触发器(trigger) 时,将隐式创建"更高层 级别的"存档点。
- 低级别上的存档点将不可用(保留工作现场),因此不会与新级别上的存档点冲突(比如存档点的标识符名称)。
- 当函数或触发器执行结束时,它创建的任何存档点都将被释放,并还原上一个存档点级别(还原工作现场)。
值得一提的是, PHP的Yii2框架, 居然支持"多次开启事务", 其实mysql是不支持"多次开启事务"的, 而是"存档点的层叠嵌套"; 更有意思的是, 这也导致框架的使用者采坑: (1)多次"开启事务", (2)"提交事务"居然失败了?
$m = new AR(); $transaction = $m->getDb()->beginTransaction(); // 返回一个对象,挂载在db下 // 巴拉巴拉一顿CRUD操作猛如虎.. $transaction = $m->getDb()->beginTransaction(); // 该对象与前者是同一个实例(单例) // 又是一顿CRUD操作猛如虎... $m->getDb()->getTransaction()->commit(); // 或者 $transaction->commit(); exit; // 等等,为什么MySQL没有找到刚才的"一顿操作"??!! // 因为 第二次beginTransaction() 创建了新的savepoint层级, // 第一次调用commit()函数, 只是 RELEASE SAVEPOINT $name // 所以需要再多调用一次 commit() 函数...直到层级为0的时候,才会真正发送 commit;语句给MYSQL服务器;
详见代码 vendor/yiisoft/yii2/db/Transaction.php
public function begin($isolationLevel = null) { $this->db->open(); if ($this->_level === 0) { if ($isolationLevel !== null) { // 设置隔离级别SET TRANSACTION ISOLATION LEVEL $level; $this->db->getSchema()->setTransactionIsolationLevel($isolationLevel); } $this->db->pdo->beginTransaction(); $this->_level = 1; return; } $schema = $this->db->getSchema(); if ($schema->supportsSavepoint()) { // 如果是InnoDB存储引擎 Yii::trace('Set savepoint ' . $this->_level, __METHOD__); $schema->createSavepoint('LEVEL' . $this->_level); } else { Yii::info('Transaction not started: nested transaction not supported', __METHOD__); } $this->_level++; }
public function commit() { if (!$this->getIsActive()) { // 没有开启事务则报错 throw new Exception('Failed to commit transaction: transaction was inactive.'); } $this->_level--; if ($this->_level === 0) { $this->db->pdo->commit(); return; } $schema = $this->db->getSchema(); if ($schema->supportsSavepoint()) { // InnoDb存储引擎 Yii::trace('Release savepoint ' . $this->_level, __METHOD__); $schema->releaseSavepoint('LEVEL' . $this->_level); } else { Yii::info('Transaction not committed: nested transaction not supported', __METHOD__); } }
YII2 的 rollback机制 也混合了savepoint, 要多次调用rollback函数才会真正rollback,很危险.
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Spring Security 源码分析九:Java config - 阶段性总结
- 金色观察丨以太坊2.0从“零阶段”到“一阶段”比想象中简单?
- 技术人员发展四阶段
- 软件需求阶段—质量全面管控
- Nginx执行阶段详细解析
- 数据中台建设成功的三个阶段
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML 编码/解码
HTML 编码/解码
html转js在线工具
html转js在线工具