Mysql事务

事务就是一组原子性的Sql查询,或者是一个独立的工作单元。事务内的语句,要么全部执行成功,要么全部执行失败。

事务举例

QQ删除好友功能可以作为一个事务。假设好友关系是一张表,张三的ID是123,李四的ID是456,那么至少要两个步骤:

1、从张三的好友列表删除李四。

2、从李四的好友列表删除张三。

上述两个操作可以打包在一个事务中,任何一个步骤失败,则必须回滚所有的事务。

可以用START TRANSACTION语句开始一个事物,然后使用COMMIT提交事务,也可以用ROLLBACK撤销所有的修改。事务SQL如下:

START TRANSACTION;
DELETE FROM friends WHERE id = 123 AND fid = 456;
DELETE FROM friends WHERE id = 456 AND fid = 123;
COMMIT;

事务的ACID特性

ACID表示原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。

原子性(atomicity):

一个事务必须是一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,不可能只执行事务的一部分。

一致性(consistency):

数据库总是从一个一致性的状态转到另一个一致性的状态。前面的例子中,如果第二个语句失败了,第一条语句即使成功执行,张三的好友也不会被删除,因为事务没有提交。

隔离性(isolation):

通常来说,一个事务对数据做的修改,在提交之前对其他事务是不可见的。

持久性(durability):

一旦事务提交,则其所作的修改就会永远保存在数据库中。此时即使系统奔溃,修改的数据也会永远保存在数据库中。

一个实现了ACID的数据库,相比没有实现ACID的数据库,通常需要更强的CPU处理能力、更大的内存和更大磁盘空间。

事务级别

在SQL标准中定义了四种隔离级别,每一种隔离级别都规定了一个事务中所作的修改,那些修改是在事务内和事务间是可见的,那些是不可见的。较低级别的隔离级别通常可以执行更高的并发,系统的开销也更低。

下面介绍四种隔离级别:

READ UNCOMMITED(未提交读):

在READ UNCOMMITED(为提交读)级别中,即使事务为提交,对其他事务也是可见的。食物可以提取未提交的数据,这也被称为脏读。这种隔离级别在实际应用中很少使用。

READ COMMITED(提交读):

大多数数据库系统的默认的隔离级别都是READ COMMITED(提交读),但Mysql不是。READ COMMITED满足一个事物开始时,只能“看见”已经提交的事物做的修改。

REPEATABLE READ(可重复读):

REPEATABLE READ(可重复读)解决了脏读的问题。该级别保证了在同一个事务中多次读取同样的记录的结果是一致的。但是又带了一个幻读的问题,所谓幻读指的是当某个事物在读取某个范围内的记录时,另外一个事物又在此范围插入了新的记录。InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题。

SERIALIZABLE(可串行化):

SERIALIZABLE(可串行化)是最高的隔离级别,他通过强制串行执行,避免了前面说的幻读问题。SERIALIZABLE会在每一行数据上加锁,所以可能导致大量的超时和锁争用的问题。实际应用很少用这个隔离级别,只有在非常需要确保数据的一致性并且不需要考虑并发的情况下,才考虑使用该级别。

死锁

死锁是指两个或者多个事务在同一资源上互相占用,并请求锁定对方占用的资源,从而导致恶性循环的现像。当多个事务以不同的顺序锁定资源时,就会产生死锁。多个事务同时锁定一个资源时,也会产生死锁。

为了死锁问题,数据库系统实现了死锁检测和死锁超时机制。越复杂的系统,比如InnoDB存储引擎,越能检测出死锁的循环依赖,并立即返回一个错误。InnoDB目前的解决死锁的办法是,将持有最少行级拍他锁的事务进行回滚。这是比较简单的死锁回滚算法。对于事务型的系统,死锁是在所难免的,所以应用程序在设计时,必须考虑死锁的问题。大多数情况下只需要重新执行因死锁回滚的事务即可。

事务日志

事务日志可以帮助提高事务的效率。使用事务日志,,存储引擎在修改表数据时只需要修改其内存拷贝,再把修改行为记录到持久硬盘上的事务日志中,而不用每次都将修改的数据本身持久到硬盘上。

事务日志是采用的追加的方式,因此写日志的操作是磁盘上一小块区域的顺序I/O,而不是随机I/O需要在磁盘多个地方移动磁头,所以采用事务日志的方式相对要快的多。

事务日志持久以后,内存中被修改的数据可以慢慢刷回到磁盘。如果数据的修改已经记录到事务日志并持久化,但数据本身还没有写回磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这部分修改的数据。

Mysql中的事务

Mysql提供了两种事务型的存储引擎:InnoDB和NDB Cluster。另外一些第三方的存储引擎也支持事务,比较知名的包括XtraDB和PBXT。

自动提交(AUTOCOMMIT)

Mysql默认采用自动提交模式。也就是说,如果不是显式的开始一个事务,则每个查询都被当做一个事务执行提交操作。Mysql在当前连接中查看AUTOCOMMIT

show variables like 'autocommit';

设置开启AUTOCOMMIT

set autocommit = 1;

当AUTOCOMMIT=0时,所有的查询都在一个查询中,知道显式的执行COMMIT提交或者ROLLBACK回滚,该事物结束,同时又开始了一个新的事务。

Mysql可以通过SET TRANSACTION ISOLATION LEVEL设置隔离级别。新的隔离级别在下一个新事务中生效。可以在配置文件中设置整个数据库的隔离级别,也可以只改变当前会话的隔离级别

Mysql> set session transaction isolation level read commit;

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

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

Mysql服务器不管理事务,事务是由存储引擎实现的。所以在同一个事务中,使用多种存储引擎是不合适的。

如果事务中混合使用了事务型和非事务型的表(例如INnoDB和MyISAM表),在正常提交时,不会有影响。但如果需要回滚,非事务型的表就无法撤销。这会导致数据库处于不一致的状态,这种状态很难修复,事务的最终结果无法却确定。

在非事务型表上执行事务回滚操作的时候,Mysql会发出一个警告:‘某些非事务型的表上的变更不能被回滚’。

隐式和显式锁定

InnoDB在事务执行过程中,随时可以执行锁定,锁只有在执行COMMIT或者ROLLBACK时才会释放,并且所有的锁一起释放,这种是隐式锁定。InnoDB会根据隔离级别在需要时自动加锁。

另外InnoDB也支持特定的语句进行显式锁定。

Mysql也支持LOCK TABLES 和UNLOCK TABLES语句,这些是服务器实现的,跟存储引擎无关。

在这里提醒一下,除了事务中禁用了AUTOCOMMIT,可以使用LOCK TABLES之外,其他任何时候,都不要显式的执行LOCK TABLES,不管使用的是什么存储引擎。

广告

JackSun

JackSun

I'm a coder.

You may also like...

No Responses

  1. BvVEj says:

    男人的天堂、高清s萝舞,电动s棒棒各种耍 http://uVU.cc/iqVo

Leave a Reply

Your email address will not be published.