标签:
今天从MySQL数据库的角度说明锁机制和事务隔离级别之间的关系。
MySQL数据库支持多种数据库引擎,但是最常用的只有MyISAM和InnoDB。由于MyISAM不支持事务,因此当我们在谈到事务隔离级别的时候,基本都是在说InnoDB。不过由于MyISAM上使用的表级锁对于理解InnoDB上的行级锁大有裨益,因此本文也会扼要介绍。
一、并发事务与事务隔离级别
相对于单线程的数据处理来说,并发事务能大大提高数据库资源的利用率,提高数据库系统的事务吞吐量,从而可以支持更多用户。但是并发也会带来一些问题:
丢失更新不能完全依靠数据库事务控制器来解决,需要应用程序对需要更新的数据加必要的锁来解决。因此,防止丢失更新是应用程序的责任。从线程并发的角度来说,应该在可能更新数据的方法上进行同步。
数据库实现事务隔离的方式,基本上可分为两种:
一种是在读取数据前,对其加锁,阻止其它事务对数据进行修改。
另一种是不加任何锁,而是通过一定机制生成一个数据请求点的一致性数据快照,并用这个快照来提供一定级别的一致性读取操作。
数据库的事务隔离越严格,并发的副作用越小,但付出的代价就越大。因为事务隔离实质上就是使事务在一定程度上“序列化”,这显然与并发是相矛盾的。为了解决上述矛盾,MySQL定义了4种事务隔离级别,分别叫:未提交读取、已提交读取、可重复读取、可序列化。具体定义请参考上一篇文章,这里不赘述了。
二、InnoDB的行级锁模式
InnoDB提供了两种类型的行级锁和与之匹配的表级锁。
需要注意,当一个事务获得一个数据表的表排他锁时,另一个事务也可以获取这个数据表的排他锁。因为两个更新数据的事务彼此不会冲突,而丢失更新的问题应该交给应用层解决。由此可见,InnoDB对锁的实现显然比字面表述更加复杂。这就是为什么我们通常称InnoDB的表级锁为意向锁的原因,它和MyISAM的表级锁有根本性区别。
至于具体加锁的操作,不在本文的讨论范围。
三、MyISAM的表级锁模式
MyISAM引擎不支持事务,因此不存在所谓的事务并发问题。MyISAM的表级锁有两种模式:表共享读锁和表排他写锁。除了语义上的不同以外,与InnoDB的区别主要是以下两点:
四、InnoDB行级锁的特殊性
能够理解以上内容,基本就对MySQL的锁机制和事物隔离有了比较准确的认知。作为补充,增加一些MySQL数据库与Oracle的区别。
InnoDB行级锁时通过给索引上的索引项来加锁实现的,这一点与Oracle不同,后者是通过在数据块中给相应的数据行加锁来实现的。这个特点意味着:只有通过索引条件检索数据,InnoDB才能使用行级锁,否则只能使用表级锁,从而极大的影响并发性能。此外,即使是访问不同记录,如果事务使用了相同的索引键也会出现锁冲突。
当我们使用范围索引并请求共享锁或排他锁的时候,对于键值不存在的记录,InnoDB会使用间隙锁。例如:
Select * From user where id>100 for update;
InnoDB不仅会给符合条件的所有记录加锁,也会给id>100的不存在的记录加间隙锁。使用间隙锁的目的主要是防止幻读的发生。这一点与MyISAM也有不同。使用MyISAM引擎被读线程加了共享读锁的数据表依然可以被其他写线程从表尾插入记录。因此,除非使用前文描述的“快照”技术,否则很难保证使用MyISAM的读操作不出现“幻读”问题。
标签:
原文地址:http://www.cnblogs.com/learnhow/p/5238172.html