网站首页技术博客

MySQL中的事务

洞天水月2023-01-10 16:40:59201人次阅读
摘要MySQL提供了两种事务型的存储引擎:InnoDB和NDB Cluster。另外还有一些第三存储引擎也支持事务,比较知名的包括XtraDB和PBXT。后面将详细讨论它们各自的此特点。 自动提交(AUTOCOMMIT) MySQL默认采用自动提交(AUTOCOMMIT)模式。也就是说,如果不是显式地开始一个事务,则每个查询都被当作一个事务执行提交操作。在当前连接中,可以通过设置AUTOCOMMI

MySQL提供了两种事务型的存储引擎:InnoDB和NDB Cluster。另外还有一些第三存储引擎也支持事务,比较知名的包括XtraDB和PBXT。后面将详细讨论它们各自的此特点。

自动提交(AUTOCOMMIT)

MySQL默认采用自动提交(AUTOCOMMIT)模式。也就是说,如果不是显式地开始一个事务,则每个查询都被当作一个事务执行提交操作。在当前连接中,可以通过设置AUTOCOMMIT变量来启用或者禁用自动提交模式:

mysq1>SHOW VARIABLES LIKE 'AUTOCOMMIT'
+---------------+-------+
| Variable name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.00 sec)
mysql> SET AUTOCOMMIT=1;

1或者ON表示启用,@或者 OFF表示禁用。当 AUTOCOMMIT=0时,所有的查询都是在一个事务中,直到显式地执行 COMMIT提交或者 ROLLBACK 回滚,该事务结束,同时又开始了另一个新事务。修改AUTOCOMMIT对非事务型的表,比如MyISAM或者内存表,不会有任何影响。对这类表来说,没有COMMIT或者ROLLBACK的概念,也可以说是相当于一直处于AUTOCOMMIT启用的模式

另外还有一些命令,在执行之前会强制执行COMMIT提交当前的活动事务。典型的例子,在数据定义语言(DDL)中,如果是会导致大量数据改变的操作,比如ALTER TABLE.就是如此。另外还有LOCK TABLES等其他语句也会导致同样的结果。如果有需要,请检查对应版本的官方文档来确认所有可能导致自动提交的语句列表。

MySQL可以通过执行SET TRANSACTION ISOLATION LEVEL命令来设置隔离级别。新的隔离级别会在下一个事务开始的时候生效。可以在配置文件中设置整个数据库的隔离级别,也可以只改变当前会话的隔离级别:

mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

MySQL能够识别所有的4个ANSI隔离级别,InnoDB引擎也支持所有的隔离级别。

在事务中混合使用存储引擎

MySQL服务器层不管理事务,事务是由下层的存储引擎实现的。所以在同一个事务中,使用多种存储引擎是不可靠的。

如果在事务中混合使用了事务型和非事务型的表(例如InnoDB和MyISAM表),在正常提交的情况下不会有什么问题。但如果该事务需要回滚,非事务型的表上的变更就无法撤销,这会导致数据库处于不一致的状态,这种情况很难修复,事务的最终结果将无法确定。所以,为每张表选择合适的存储引擎非常重要。

在非事务型的表上执行事务相关操作的时候,MySQL通常不会发出提醒,也不会报错有时候只有回滚的时候才会发出一个警告:“某些非事务型的表上的变更不能被回滚”但大多数情况下,对非事务型表的操作都不会有提示。

隐式和显式锁定

InnoDB采用的是两阶段锁定协议(two-phase locking protocol)。在事务执行过程中,随时都可以执行锁定,锁只有在执行COMMIT或者ROLLBACK的时候才会释放,并且所有的锁是在同一时刻被释放。前面描述的锁定都是隐式锁定,InnoDB会根据隔离级别在需要的时候自动加锁。

另外,lnnoDB也支持通过特定的语句进行显式锁定,这些语句不属于SQL规范:

SELECT …… LOCK IN SHARE MODE

MySQL也支持LOCK TABLES和UNLOCK TABLES语句,这是在服务器层实现的,和存储引擎无关。它们有自己的用途,但并不能替代事务处理。如果应用需要用到事务,还是应该选择事务型存储引擎。

SELECT …… FOR UPDATE

经常可以发现,应用已经将表从MyISAM转换到InnoDB,但还是显式地使用LOCK TABLES语句。这不但没有必要,还会严重影响性能,实际上InnoDB的行级锁工作得更好。

LOCK TABLES和事务之间相互影响的话,情况会变得非常复杂,在某些MySOL版本中甚至会产生无法预料的结果。因此,本文建议,除了事务中禁用了AUTOCOMMIT可以使用LOCK TABLES之外,其他任何时候都不要显式地执行LOCK TABLES,不管使用的是什么存储引擎。

上一篇:Mysql死锁

下一篇:MVCC多版本并发控制

文章评论