首页 > 代码库 > MySQL具体解释(14)----------事务处理

MySQL具体解释(14)----------事务处理

前言:前一篇文章关于事务处理的博文没有写清楚,读起来非常晦涩。非常难理解,所以有整理了一些资料,帮助理解。见谅!

 

关于MySQL事务处理学习记

START TRANSACTION

COMMIT

ROLLBACK

语法

 START TRANSACTION    | 

BEGIN [WORK]     

COMMIT   [WORK]    [AND [NO] CHAIN]    [  [NO] RELEASE  ]

ROLLBACK  [WORK]  [AND  [NO]  CHAIN]   [  [NO] RELEASE  ]   

SET AUTOCOMMIT = {0 | 1}

 

START TRANSACTION或BEGIN语句能够開始一项新的事务。

 

COMMIT能够提交当前事务。是变更成为永久变更。

 

ROLLBACK能够 回滚当前事务,取消其变更。

 

SET AUTOCOMMIT语句能够禁用或启用默认的autocommit模式,用于当前连接。

自选的WORK关键词被支持。用于COMMIT和RELEASE。与CHAIN和RELEASE子句。

 

CHAIN和RELEASE能够被用于对事务完毕进行附加控制。

 

Completion_type系统变量的值决定了默认完毕的性质。

 

AND CHAIN子句会在当前事务结束时。立马启动一个新事务。而且新事务与刚结束的事务有同样的隔离等级。

 

RELEASE子句在终止了当前事务后。会让server断开与当前client的连接。包括NO关键词能够抑制CHAIN或RELEASE完毕。

假设completion_type系统变量被设置为一定的值。使连锁或释放完毕能够默认进行,此时NO关键词实用。

 

默认情况下,MySQL採用autocommit模式执行。这意味着。当您执行一个用于更新(改动)表的语句之后。MySQL立马把更新存储到磁盘中。

 

假设您正在使用一个事务安全型的存储引擎(如InnoDB, BDB或NDB簇)。则您能够使用下面语句禁用autocommit模式:

SET AUTOCOMMIT=0; 通过把AUTOCOMMIT变量设置为零。禁用autocommit模式之后。您必须使用COMMIT把变更存储到磁盘中。或着假设您想要忽略从事务開始进行以来做出的变更。使用ROLLBACK。

 

假设您想要对于一个单一系列的语句禁用autocommit模式。则您能够使用START TRANSACTION语句:

 

START TRANSACTION;

SELECT @A:=SUM(salary) FROM table1 WHERE type=1;

UPDATE table2 SET summary=@A WHERE type=1; COMMIT;

使用START TRANSACTION,autocommit仍然被禁用,直到您使用COMMIT或ROLLBACK结束事务为止。

然后autocommit模式恢复到原来的状态。

 

BEGIN和BEGIN WORK被作为START TRANSACTION的别名受到支持,用于对事务进行初始化。

START TRANSACTION是标准的SQL语法。而且是启动一个ad-hoc事务的推荐方法。

BEGIN语句与BEGIN关键词的使用不同。BEGIN关键词能够启动一个BEGIN...END复合语句。后者不会開始一项事务。

 

您也能够依照例如以下方法開始一项事务:

START TRANSACTION WITH CONSISTENT SNAPSHOT;

WITH CONSISTENT SNAPSHOT子句用于启动一个一致的读取。用于具有此类功能的存储引擎。

 

眼下,该子句仅仅适用于InnoDB。该子句的效果与公布一个START TRANSACTION,后面跟一个来自不论什么InnoDB表的SELECT的效果一样。

 

開始一项事务会造成一个隐含的UNLOCK TABLES被运行。

为了获得最好的结果,事务应仅仅使用由单一事务存储引擎管理的表运行。

否则,会出现下面问题:

 

假设您使用的表来自多个事务安全型存储引擎(比如InnoDB和BDB)。而且事务隔离等级不是SERIALIZABLE,则有可能当一个事务提交时。其他正在进行中的、使用相同的表的事务将仅仅会发生由第一个事务产生的变更。

也就是。用混合引擎不能保证事务的原子性。并会造成不一致。(假设混合引擎事务不常常有,则您能够依据须要使用

SET TRANSACTION ISOLATION LEVEL把隔离等级设置到SERIALIZABLE。)

 

假设您在事务中使用非事务安全型表,则对这些表的不论什么变更被立马存储,不论autocommit模式的状态怎样。

假设您在更新了事务中一个事务表之后。公布一个ROLLBACK语句,则会出现一个ER_WARNING_NOT_COMPLETE_ROLLBACK警告。

对事务安全型表的变更被 回滚,可是对非事务安全型表没有变更。

每一个事务被存储在一个组块中的二进制日志中,在COMMIT之上。被回滚的事务不被计入日志。(例外情况:对非事务表的更改不会被 回滚。假设一个被回滚的事务包含对非事务表的更改,则整个事务使用一个在末端的ROLLBACK语句计入日志,以确保对这些表的更改进行复制。)

 

您能够使用SET TRANSACTION ISOLATION LEVEL更改事务的隔离等级。

 

回滚能够慢速执行。在用户没有明白要求时,也能够进行回滚(比如。当发生错误时)。因此,在明白地和隐含的(ROLLBACK SQL命令)回滚时。SHOW PROCESSLIST会在Stage列中显示Rolling back。用于连接。

 


    事务处理和并发性

1.1.        基础知识和相关概念

1 )所有的表类型都能够使用锁。可是仅仅有 InnoDB 和 BDB 才有内置的事务功能。

2 )使用 begin 開始事务,使用 commit 结束事务。中间能够使用 rollback 回滚事务。

3 )在默认情况下, InnoDB 表支持一致读。

SQL 标准中定义了 4 个隔离级别: read uncommited 。 read commited , repeatable read 。 serializable 。

read uncommited 即脏读。一个事务改动了一行。还有一个事务也能够读到该行。

假设第一个事务运行了回滚,那么第二个事务读取的就是从来没有正式出现过的值。

?

read commited 即一致读。试图通过仅仅读取提交的值的方式来解决脏读的问题,可是这又引起了不可反复读取的问题。

一个事务运行一个查询。读取了大量的数据行。

在它结束读取之前,还有一个事务可能完毕了对数据行的更改。当第一个事务试图再次运行同一个查询,server就会返回不同的结果。

repeatable read 就可以反复读。在一个事务对数据行运行读取或写入操作时锁定了这些数据行。

可是这样的方式又引发了幻想读的问题。

由于仅仅能锁定读取或写入的行,不能阻止还有一个事务插入数据,后期运行相同的查询会产生很多其它的结果。

serializable 模式中,事务被强制为依次运行。这是 SQL 标准建议的默认行为。

4 )假设多个事务更新了同一行。就能够通过回滚当中一个事务来解除死锁。

5 ) MySQL 同意利用 set transaction 来设置隔离级别。

6 )事务仅仅用于 insert 和 update 语句来更新数据表。不能用于对表结构的更改。运行一条更改表结构或 begin 则会马上提交当前的事务。

7 )全部表类型都支持表级锁,可是 MyISAM 仅仅支持表级锁。

8 )有两种类型的表级锁:读锁和写锁。

读锁是共享锁。支持并发读。写操作被锁。

写锁是独占锁,上锁期间其它线程不能读表或写表。

8 )假设要支持并发读写,建议採用 InnoDB 表,由于它是採用行级锁,能够获得很多其它的更新性能。

9 )非常多时候,能够通过经验来评估什么样的锁相应用程序更合适。只是通常非常难说一个锁比别的更好。这全都要根据应用程序来决定。不同的地方可能须要不同的锁。

当前 MySQL 已经支持 ISAM, MyISAM, MEMORY (HEAP) 类型表的表级锁了。 BDB 表支持页级锁, InnoDB 表支持行级锁。

10 ) MySQL 的表级锁都是写锁优先,并且是採用排队机制,这样不会出现死锁的情况。对于 InnoDB 和 BDB 存储引擎来说,是可能产生死锁的。这是由于 InnoDB 会自己主动捕获行锁。 BDB 会在运行 SQL 语句时捕获页锁的。而不是在事务的開始就这么做。

1.2.        不同锁的优缺点及选择

行级锁的长处及选择 :

1 )在非常多线程请求不同记录时降低冲突锁。

2 )事务回滚时降低改变数据。

3 )使长时间对单独的一行记录加锁成为可能。

行级锁的缺点 :

1 )比页级锁和表级锁消耗很多其它的内存。

2 )当在大量表中使用时。比页级锁和表级锁更慢。由于他须要请求很多其它的所资源。

3 )当须要频繁对大部分数据做 GROUP BY 操作或者须要频繁扫描整个表时。就明显的比其他锁更糟糕。

4 )使用更高层的锁的话,就能更方便的支持各种不同的类型应用程序,由于这样的锁的开销比行级锁小多了。

5 )能够用应用程序级锁来取代行级锁。比如 MySQL 中的 GET_LOCK() 和 RELEASE_LOCK() 。

但它们是劝告锁(原文: These are advisory locks ),因此仅仅能用于安全可信的应用程序中。

6 )对于 InnoDB 和 BDB 表, MySQL 仅仅有在指定用 LOCK TABLES 锁表时才使用表级锁。

在这两种表中,建议最好不要使用 LOCK TABLES 。由于 InnoDB 自己主动採用行级锁。 BDB 用页级锁来保证事务的隔离。

表锁的长处及选择:

1 )非常多操作都是读表。

2 )在严格条件的索引上读取和更新。当更新或者删除能够用单独的索引来读取得到时: UPDATE tbl_name SET column=value WHERE unique_key_col=key_value;DELETE FROM tbl_name WHERE unique_key_col=key_value;

3 ) SELECT 和 INSERT 语句并发的运行,可是仅仅有非常少的 UPDATE 和 DELETE 语句。

4 )非常多的扫描表和对全表的 GROUP BY 操作,可是没有不论什么写表。

表锁的缺点:

1 )一个client提交了一个须要长时间执行的 SELECT 操作。

2 )其它client对同一个表提交了 UPDATE 操作。这个client就要等到 SELECT 完毕了才干開始运行。

3 )其它client也对同一个表提交了 SELECT 请求。因为 UPDATE 的优先级高于 SELECT 。所以 SELECT 就会先等到 UPDATE 完毕了之后才開始运行,它也在等待第一个 SELECT 操作。

1.3.        怎样避免锁的资源竞争

1 )让 SELECT 速度尽量快,这可能须要创建一些摘要表。

2 )启动 mysqld 时使用參数 --low-priority-updates 。这就会让更新操作的优先级低于 SELECT 。

这样的情况下,在上面的如果中,第二个 SELECT 就会在 INSERT 之前运行了,并且也无需等待第一个 SELECT 了。

3 )能够运行 SET LOW_PRIORITY_UPDATES=1 命令,指定全部的更新操作都放到一个指定的链接中去完毕。

4 )用 LOW_PRIORITY 属性来减少 INSERT 。 UPDATE 。 DELETE 的优先级。

5 )用 HIGH_PRIORITY 来提高 SELECT 语句的优先级。

6 )从 MySQL 3.23.7 開始,能够在启动 mysqld 时指定系统变量 max_write_lock_count 为一个比較低的值。它能强制暂时地提高表的插入数达到一个特定值后的全部 SELECT 操作的优先级。它同意在 WRITE 锁达到一定数量后有 READ 锁。

7 )当 INSERT 和 SELECT 一起使用出现故障时。能够转而採用 MyISAM 表,它支持并发的 SELECT 和 INSERT 操作。

8 )当在同一个表上同一时候有插入和删除操作时。 INSERT DELAYED 可能会非常实用。

9 )当 SELECT 和 DELETE 一起使用出现故障时, DELETE 的 LIMIT 參数可能会非常实用。

10 )运行 SELECT 时使用 SQL_BUFFER_RESULT 有助于减短锁表的持续时间。

11 )能够改动源码 `mysys/thr_lock.c‘ ,仅仅用一个所队列。这样的情况下,写锁和读锁的优先级就一样了。这对一些应用可能有帮助。

 

 

MySQL具体解释(14)----------事务处理