Mysql事务的自动提交与手动提交

自动提交系统变量AUTOCOMMIT

AUTOCOMMIT=ON|OFF系统变量控制自动提交功能的开启或关闭

自动提交模式

set autocommit=on表示在当前会话开启自动提交模式,在这种模式下,每条DML语句都是单独的一个事务,若想在这种模式下实现将多条DML语句放在同一事务中,需要使用BEGIN; statement; [statement;] ... COMMIT;这种形式来将多条DML语句封装在一起。另外,BEGIN;在使用的时候有个小技巧,在使用BEGIN;开启新事务时会对前面的事务进行隐式提交,因此也可以用BEGIN;来提交事务,只是其副作用是会开启新的事务。当然,如果想要不保存当前事务所做的更改,使用ROLLBACK;即可回退。

手动提交模式

set autocommit=off表示在当前会话使用手动提交模式,在这种模式下,若不使用COMMIT;或其他具有隐式提交属性的语句(例如上述BEGIN;)就不会提交DML语句对数据的改变,提交之前允许使用ROLLBACK;对事务进行回滚。由于BEGIN;带有隐式提交属性,因此在这种模式下BEGIN;COMMIT;是等价的。

总结

综合对以上两种提交模式的特性的分析,唯独像BEGIN; statement_list; BEGIN; statement_list; BEGIN;这种形式的应用代码对于两种提交模式在保证事务的原子性上是等价的。因此,个人比较推荐使用BEGIN;来作为代码中事务的间隔标志,以防代码受到AUTOCOMMIT系统变量的影响。

小拓展

Mysql官方文档中描述关于使用LOCK TABLES获取锁和FLUSH TABLES的区别时,这句话困扰了我许久:
Beginning a transaction causes table locks acquired with LOCK TABLES to be released, as though you had executed UNLOCK TABLES.
事务的开始会导致LOCK TABLES获取的表锁被释放,即便你已经执行过UNLOCK TABLES
摘自:https://dev.mysql.com/doc/refman/5.7/en/flush.html#flush-binary-logs

根据逻辑和语境,感觉这里很有可能是写错了,应该是as though you had not executed UNLOCK TABLES,即便是你还没执行过UNLOCK TABLES来释放表锁,开始事务会也可以释放锁。

最终经测试发现,这里所说的开始事务必须是用BEGIN;来显式地开启事务(否则当前会话无法进行任何事务,只能执行select查询),才能够释放表锁。

测试代码如下(以lock tables ... read获取读锁为例):

mysql> use test;
Database changed
mysql> select * from a;
Empty set (0.00 sec)

mysql> select * from b;
Empty set (0.00 sec)

mysql> lock table a read;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into b values(1);
ERROR 1100 (HY000): Table 'b' was not locked with LOCK TABLES
mysql> 
mysql> 
mysql> insert into a values(1);
ERROR 1099 (HY000): Table 'a' was locked with a READ lock and can't be updated
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into a values(1);
Query OK, 1 row affected (0.01 sec)

mysql> select * from a;
+------+
| id   |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

你可能感兴趣的:(Mysql事务的自动提交与手动提交)