首页 > 代码库 > MySQL事务概述

MySQL事务概述

为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处。LaplaceDemon/SJQ。

http://www.cnblogs.com/shijiaqi1066/p/3858050.html

 

 

 

1 事务(Transaction)概述

1.1 数据库事务的四个特性:ACID

原子性(Atomicity)

整个事务中的所有操作,要么全部完成,要么全部不完成。

一致性(Consistency)

数据库一致性(Database Consistency)是指事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。

隔离性(Isolation)

又称为孤立性。多个人执行多个事务,事务需要隔离。即事务不能同时进行。

持久性(Durability)

保证即便断电,也能正常工作。

 

 

1.2 事务的分类

扁平事务

最典型的事务,由BEGIN WORK开始,由COMMIT WORK或ROLLBACK WORK结束,其间的操作都是原子的。要么执行,要么回滚。

带有保存点的事务

在基于扁平事务的基础上,允许在事务执行过程中回滚到事务中较早的一个状态。

链事务

保存点事务的一种变种。保存点事务在系统崩溃时,所有的保存点都是易失的,即系统恢复时,事务需要从开始出重新执行,而不能从最近的保存点继续执行。

链事务指的是在提交事务时,释放不需要的数据对象,将必要的处理上下文隐式地传给下一个要开始的事务。提交事务和开始下一个事务将合并为一个原子操作。即下一个事务将看到上一个事务的结果,就好象在一个事务中进行一样。

链事务与带有保存点的事务不同,带有保存点的事务能回滚到任意正确的保存点。而链事务中的回滚仅限于当前保存点。

嵌套事务

嵌套事务是一个层次结构框架。有一个顶层事务控制各个层次的事务。顶层事务之下嵌套的事务被称为子事务。

父事务回滚,子事务也会被回滚。即子事务具备,ACI的特性,不具备D的特性。

分布式事务

分布式事务是在分布式环境下运行的扁平事务。

 

对于InnoDB存储引擎,支持扁平事务,带有保存点的事务、链事务、分布式事务。但不支持嵌套事务。

 

 

 

1.3 事务的隔离级别

ANSI/ISO SQL标准(SQL92)定义了四种事务隔离级别(transaction isolation level)。这些事务隔离级别是针对三种现象定义的,在并发事务执行时,需要阻止这三种现象中的一种或多种发生。

三种需要阻止的现象(preventable phenomena)是:

脏读取(dirty read):简称“脏读”。指一个事务读取了被其他事务写入但还未提交的数据。

不可重复读取(nonrepeatable read):一个事务再次读取其之前曾经读取过的数据时,发现数据已被其他已提交的事务修改或删除。

不存在读取(phantom read):简称“幻读”。事务按照之前的条件重新查询时,返回的结果集中包含其他已提交事务插入的满足条件的新数据。

 

辨析:不可重复读与幻读的区别

不可重复读与幻读,这种现象有些类似。

不可重复读的重点是修改:同样的条件, 读取过的数据, 再次读取出来发现值不一样。若需要避免该现象,只需要锁住满足条件的记录。

幻读的重点在于新增或者删除:同样的条件, 第1次和第2次读出来的记录数不一样。若需要避免该现象,要锁住满足条件及其相近的记录,或直接锁表。 

 

 

SQL标准定义了4类隔离级别如下:

Read Uncommitted(未提交读)

所有事务都可以看到其他未提交事务的执行结果,即允许脏读。该隔离级别,很少实际应用。

Read Committed(已提交读)

一个事务只能看见已经提交事务所做的改变。即不允许脏读。但允许不可重复读,因为其他事务在当前事务的处理其间可能会有新的commit,所以前后的select可能返回不同结果。

Repeatable Read(可重复读)

确保一个事务在重复读取数据时,对重复读取到的数据行的值是不变的。避免了不可重复读。但无法避免幻读。即一个事务重复读取数据时,可能会发现有新的“幻影”行。

Serializable(可串行化)

串行的对事务进行处理。强制事务排序,使之不可能相互冲突,从而解决幻读问题。

只有当事务提交后,其他事务才能从数据库中查看数据的变化。

这是最高的隔离级别,在这个级别,可能导致大量的超时现象和锁竞争。

 

不同级别的隔离方法可以避免一定的现象:

           \ 现象   

隔离级别  \

脏读取不可重复读取幻读
未提交读 允许允许允许
已提交读 不允许允许允许
可重复读 不允许不允许允许
可串行化 不允许不允许不允许

 

 

 

2 MySQL的事务

2.1 MySQL的事务处理命令

在命令行交互环境下,或存储过程中,可以使用如下命令方便的操作事务。

初始化事务

命令:START TRANSACTION;

 

事务回滚

命令:ROLLBACK;

 

提交事务

命令:COMMIT;

 

设置保存点

命令:SAVEPOINT identifer

 

删除事务的保存点

命令:RELEASE SAVEPOINT identifer

 

回滚至保存点

命令:ROLLBACK TO [SAVEPOINT] identifer

 

自动提交

在MySQL中,若不更改其自动提交变量,则系统会自动向数据库提交结果。

关闭自动提交:SET AUTOCOMMIT = 0;

关闭自动提交之后,只有使用COMMIT命令后,才会提交事务。

 

查看AUTOCOMMIT值:

命令:select @@autocommit;

wps_clip_image-28302

 

或命令:show variables like ‘autocommit‘;

wps_clip_image-28305

 

 

 

2.2 事务的实现

事务的隔离性由数据库的锁来实现。原子性,一致性,持久性由数据库的redo logundo log来完成。

  • redo log称为重做日志,用于保证事务的原子性和持久性。
  • undo log用来保证事务的一致性。

 

 

2.3 MySQL的隔离级别

MySQL的默认事务隔离级别为Repeatable Read(可重复读)

MySQL中InnoDB存储引擎结合了MVCC和Next-Key Lock锁的算法,避免了幻读的产生。InnoDB存储引擎在默认的Repeatable Read的事务隔离级别下,已经能完全保证事务的隔离性要求。即达到了Serializable隔离级别。

查看当前数据库使用的隔离级别。global.tx_isolation变量表示全局事务。tx_isolation表示当前会话的事务。

命令:select @@global.tx_isolation , @@tx_isolation;

wps_clip_image-22562

 

修改当前数据库使用的隔离级别,使用SET语句对tx_isolation变量进行设置。用户需要有SUPER权限,才可以执行进行隔离级别的修改。

基本命令格式:SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }

 

在默认情况下,SET TRANSACTION会为下一个事务(还未开始)设置隔离等级。

若使用GLOBAL关键词,则语句会设置全局性的默认事务等级,用于从该点以后创建的所有新连接原有的连接不受影响。

若使用SESSION可以设置默认事务等级,用于对当前连接的事务。

 

例:将当前会话的事务隔离级别设置为Read Uncommitted(未提交读)。

命令:SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

 

 

2.4 分布式事务

InnoDB存储引擎支持XA事务,通过XA事务实现分布式事务。使用分布式事务时,InnoDB存储引擎的隔离级别必须设置为SERIALIZABLE

XA事务允许不同数据库的分布式事务,只要参与在全局事务中的每个节点都支持XA事务。Oracle,SQL Server都支持XA事务。

XA事务由一个或多个资源管理器、一个事务管理器以及一个应用程序组成。

  • 资源管理器:提供访问事务资源的方法。通常一个数据库就是一个资源管理器。
  • 事务管理器:协调参与全局事务中的各个事务。需要和参与全局事务的所有资源管理器进行通信。
  • 应用程序:定义事务的边界。

 

 

2.5 事务与性能

很多应用其实是不需要事务的。例,在数据仓库中,若没有ETL这些操作,只是简单的报表查询是不需要事务的。

传统观点认为,事务隔离级别越高,数据越安全,但性能就越慢。事务隔离级别越低,性能就越快,但数据越不安全。

但在Jim Gray在《Transaction Processing》一书中指出,REPEATABLE READ 与SERIALIZABLE 的开销几乎是一样的。SERIALIZABLE 甚至可能更优。READ UNCOMMITTED的隔离级别也不会有太大的性能提升。

 

 

2.6 锁的简要介绍与使用

数据库锁也就是所谓的悲观锁。

 

2.6.1 锁的类型

读锁

又称共享锁、S锁。被锁定对象只允许被读,不允许被写。

若事务T对数据对象A加上读锁,则事务T可以读A但不能修改A,其他事务只能再对A加读锁,而不能加写锁,直到事务T释放A上的读锁。

写锁

又称排他锁、X锁。

若事务T对数据对象A加上写锁,事务T可以读A也可以修改A,其他事务不能读A,也不能再对A加任何锁,直到T释放A上的锁。

 

2.6.2 表级锁

操作对象是数据表,是系统开销最低但并发性最低的一个锁策略。

命令格式:LOCK TABLES 表1 锁类型, 表2 锁类型 ... ;

LOCK命令可以同时对多张表加锁。锁类型为READ、WRITE。

 

例:对student表添加读锁。

命令:lock tables student read;

 

例:对student表添加写锁。

命令:lock tables student write;

 

在用LOCK TABLES给表显式加表锁时,必须同时取得所有涉及到表的锁,并且MySQL不支持锁升级。也就是说,在执行LOCK TABLES后,只能访问显式加锁的这些表,不能访问未加锁的表;同时,如果加的是读锁,那么只能执行查询操作,而不能执行更新操作。其实,在自动加锁的情况下也基本如此,MyISAM总是一次获得SQL语句所需要的全部锁。这也正是MyISAM表不会出现死锁(Deadlock Free)的原因。

 

解锁

命令:UNLOCK TABLES;

UNLOCK命令会释放所有处于锁定状态的数据表。

 

 

2.6.3 行级锁

操作对象是数据表中的一行。行级锁对系统开销较大,处理高并发较好。

 

行级别的读锁

命令格式:SELECT ... LOCK IN SHARE MODE;

MySQL会对查询结果集中每行都添加共享锁。

 

行级别的写锁

命令格式:SELECT ... FOR UPDATE;

MySQL会对查询结果集中每行都添加排他锁,在事物操作中,任何对记录的更新与删除操作会自动加上排他锁。

 

 

2.6.4 死锁

多个资源的并发经常会发生死锁现象。

表级锁是不会产生死锁的。MyISAM使用表级锁模拟事务是安全的。

InnoDB引擎拥有自动检查死锁的功能。当发现死锁现象,会自动解决死锁问题。

 

 

2.6.5 MySQL伪事务

由于MyISAM存储引擎可以支持表锁(不支持行级锁)。可以使用表级锁模拟事务。这种模拟的事务侧重点在于操作的隔离。这不是真正的事务,不具备回滚的操作。

表级锁是不会产生死锁,可以安全使用。

 

 

 

2.7 MVCC

MVCC,Multiversion Currency Control,即多版本并发控制。

一般情况下,事务性储存引擎不是只使用表锁,行加锁的处理数据,而是结合了MVCC机制,以处理更多的并发问题。Mvcc处理高并发能力最强,但系统开销比最大(较表锁、行级锁),这是最求高并发付出的代价。

在Mysql中MVCC是在Innodb存储引擎中得到支持的,Innodb为每行记录都实现了三个隐藏字段:

6字节的事务ID(DB_TRX_ID )

7字节的回滚指针(DB_ROLL_PTR)

隐藏的ID

使用这三个字段,利用类似于乐观锁的机制实现了近似的MVCC机制。具体原理参看相关参考资料。

 

 

 

关于MVCC的一些参考资料:

http://coolshell.cn/articles/6790.html

http://www.jayxu.com/2012/03/13/13326/

http://jishu.zol.com.cn/2960.html

http://blog.csdn.net/chen77716/article/details/6742128

 

 

 

为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处。LaplaceDemon/SJQ。

http://www.cnblogs.com/shijiaqi1066/p/3858050.html