一:隔离级别
READ UNCOMMITTED(未提交读)
在READ UNCOMMITTED级别下,在一个事务中的修改,即时没有提交,对其他事务也多是可见的。事务可以读取未提交的数据,这也称为脏读(Dirty Read)。这个级别会导致很多问题,而且从性能上来说,也不会比其他级别好太多,除非有非常必要的理由,在实际应用中一般很少用到。
READ COMMITTED(提交读)
大多数据库系统的默认隔离级别都是READ COMMITTED(但MySQL不是)。READ COMMITTED满足事务的隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改,对其他事务是不可见的。这个级别也叫做不可重复读(nonrepeatable read),因为两次执行相同的查询结果,可能会得到不一样的数据。
REPEATABLE READ(可重复读)
REPEATABLE READ解决了脏读的问题。该级别保证了在同一个事务中多次读取相同记录的结果是一样的。但理论上,可重复读仍然无法解决幻读的问题。所谓脏读,指的是当某个事务在读取某个范围的数据时,另外一个事务又在该范围插入了新的记录 。当之前的事务在此读取该范围时,会产生幻读行(Phantom Row)。InnoDB和XtraDB存储引擎通过版本并发控制MVCC(Multiversion Concurrency Control)解决了幻读问题。可重复读诗MySQL的默认事务隔离级别。
SERIALIZABLE(可串行化)
SERIALIZABLE是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。简单来说,SERIALIZABLE会在读区每一行数据上都加索,所以可能导致大量的超时和锁争用问题。实际应用中也很少用到这个隔离级别,只有在非常要求确保数据的一致性而且不考虑并发的情况下,才考虑到用该级别。
二:死锁
死锁是指两个或多个事务在同一资源上互相占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序锁定资源时,就可能会产生死锁。多个事务同时锁定同一个资源时,也会产生死锁。例如下面的例子:
事务1:
START TRANSACTION;
UPDATE StockPrice SET close = 45.50 WHERE stock_id = 1;
UPDATE StockPrice SET close = 19.80 WHERE stock_id = 2;
事务2:
START TRANSACTION;
UPDATE StockPrice SET close = 20.50 WHERE stock_id = 2;
UPDATE StockPrice SET close = 47.80 WHERE stock_id = 1;
如果凑巧,两个事务都执行了第一条UPDATE语句,同时也锁定了该行数据,接着每个事务都尝试去执行第二条UPDATE语句,却发现改行已经被对方锁定,然后两个事务都等待对方释放锁,同时又都持有对方需要的锁,则陷入死循环。除非有外部因素介入才可能解决死锁;
InnoDB目前处理死锁的方式是:将持有最少行级排他锁的事务进行回滚(这也是相对比较简单的死锁回滚算法)。
死锁发生以后,只有部分或者完全回滚其中一个事务,才能打破死锁。对于大多事务型的系统,这是无法避免的。所以应用程序在设计时必须考虑如何避免和处理死锁。大多数情况下,只需要重新执行因死锁回滚的事务即可。
三:MySQL中的事务
MySQL提供了两种事务类型的存储引擎:InnoDB和NDB Cluster。另外还有一些第三方的存储引擎也支持事务,例如比较知名的XtraDb和PBXT。
自动提交(AUTOCOMMIT)
MySQL默认采用自动提交(AUTOCOMMIT)模式。也就是说,如果不是hi显示的开始一个事务(START TRANSACTION),则每个查询都被当成一个事务执行提交操作。在当前连接中,可以通过设置AUTOCOMMIT变量来启用或禁止自动提交模式:
1或者ON表示开启,0或者OFF表示禁止。当AUTOCOMMIT=0时,所有的查询都是在一个事务中,直到显示的执行COMMIT或ROLLBACK回滚,该事务结束,同时又开始另一个新事事务。
注:修改AUTOCOMMIT对非事务型的表,比如MyISAM不会有任何影响。对这类表来说,没有COMMIT或ROLLBACK的概念。
另外,还有一下命令,在执行之前会强制执行COMMIT提交当前的活动事务,比如DDL语句,ALTER TABLE导致大量数据改变的操作。
MySQL可以通过 SET TRANSACTION ISOLATION LEVEL命令来设置隔离级别。新的隔离级别在下一个事务开始的时候生效。可以在配置文件中设置整个数据库的隔离级别,也可以指改变当前回话的隔离级别:
mysql> SET TRANSACTION ISOLATION LEVEL READ COMMITED;
四:在事务中混合使用存储引擎
MySQL服务层不管理事务,事务是由下层的存储引擎实现的。所以在同一个事务中,使用多种存储引擎室不可靠的。
如果在一个事务中同时使用了事务型和非事务型的表(比如InnoDB和MySIAM表),在正常提交的情况下不会有什么问题。注:在非事务型的表上执行事务相关操作,MySQL不会发生提醒。但是在回滚时会发出一个警告。
但是要回滚该事务,非事务型的表上的变更就会无法撤销,这回导致数据库处于不一致的状态,这种情况很难修复,事务的结果最终也将无法确定。所以,为每张表选择合适的存储引擎非常重要。
关于更深入的事务执行,等小爷研究后了再来更新...(不会太久)