您的位置:首页 > 数据库 > MySQL

MySQL详解(14)----------事务处理

2015-07-06 15:20 399 查看
前言:前一篇文章关于事务处理的博文没有写清楚,读起来很晦涩,很难理解,所以有整理了一些资料,帮助理解,见谅!



关于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子句在终止了当前事务后,会让服务器断开与当前客户端的连接。包含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 即一致读,试图通过只读取提交的值的方式来解决脏读的问题,但是这又引起了不可重复读取的问题。

一个事务执行一个查询,读取了大量的数据行。在它结束读取之前,另一个事务可能完成了对数据行的更改。当第一个事务试图再次执行同一个查询,服务器就会返回不同的结果。

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 )一个客户端提交了一个需要长时间运行的 SELECT 操作。

2 )其他客户端对同一个表提交了 UPDATE 操作,这个客户端就要等到 SELECT 完成了才能开始执行。

3 )其他客户端也对同一个表提交了 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' ,只用一个所队列。这种情况下,写锁和读锁的优先级就一样了,这对一些应用可能有帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: