深入 MySQL (三) 事务

从前文,我们了解到有一部分存储引擎是支持事务的。本文我们将探讨事务的重要概念以及实现原理。

事务

ACID概念

ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)

隔离性和隔离级别

SQL标准里定义了四种事务隔离级别:

  • 读未提交:一个事务还没提交时,它做的变更就能被别的事务看到;
  • 读提交:一个事务提交之后,它做的变更才会被其他事务看到;
  • 可重复读:一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的;
  • 串行化:对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

四种隔离级别区别:

隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读
读未提交 Y Y Y N
读提交 N Y Y N
可重复读 N N Y N
串行化 N N N Y

MySQL中的事务

MySQL提供了两种事务型存储引擎:InnoDB 和 NDB Cluster,而MyISAM并不支持事务。

MVCC与事务隔离实现

四种隔离级别的在InnoDB实现:
- 读未提交:直接返回记录上的最新值,没有视图概念;
- 读提交:在每个SQL语句开始执行的时候创建视图;
- 可重复读:在事务启动时创建视图,整个事务存在期间都用这个视图;(注意,InnoDB利用MVCC已经在可重复读隔离级别下避免了幻读问题!!注意和上边的表格内容区分清楚!!!)
- 串行化:隔离级别下直接用加锁的方式来避免并行访问。

这个所谓的视图其实是通过多版本并发控制(MVCC)来实现。(详情见《高性能MySQL》第三版 1.4 多版本并发控制)

事务的启动

事务启动方式:

  • 1.显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。
  • 2.set autocommit=0,这个命令会将这个线程的自动提交关掉(注意,仅影响当前线程。)。这意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。一般建议总是使用 set autocommit=1, 然后通过显式语句的方式来启动事务。

长事务会导致数据库空间,并且占用所资源,生产中应该尽量避免长事务。查询长事务方法:

// 查询超过60秒的事务
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60

查看修改事务隔离级别

MySQL默认的事务隔离级别是可重复读(REPEATABLE READ)。

可以通过sql查看MySQL事务隔离级别:

show variables like "%isolation%";

MySQL提供了SET TRANSACTION语句,该语句可以改变单个会话或全局的事务隔离级别。语法格式如下:

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

其中,SESSION 和 GLOBAL 关键字用来指定修改的事务隔离级别的范围:

  • SESSION:表示修改的事务隔离级别将应用于当前 session(当前 cmd 窗口)内的所有事务;
  • GLOBAL:表示修改的事务隔离级别将应用于所有 session(全局)中的所有事务,且当前已经存在的 session (包括当前session)不受影响;
  • 如果省略 SESSION 和 GLOBAL,表示修改的事务隔离级别将应用于当前 session 内的下一个还未开始的事务。

任何用户都能改变会话的事务隔离级别,但是只有拥有 SUPER 权限的用户才能改变全局的事务隔离级别。

其他注意

延伸阅读

-理解MySQL的锁机制和事务原理


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 duval1024@gmail.com

×

喜欢就点赞,疼爱就打赏