事务隔离级别(二)

今天从MySQL数据库的角度说明锁机制和事务隔离级别之间的关系。

MySQL数据库支持多种数据库引擎,但是最常用的只有MyISAM和InnoDB。由于MyISAM不支持事务,因此当我们在谈到事务隔离级别的时候,基本都是在说InnoDB。不过由于MyISAM上使用的表级锁对于理解InnoDB上的行级锁大有裨益,因此本文也会扼要介绍。

一、并发事务与事务隔离级别

相对于单线程的数据处理来说,并发事务能大大提高数据库资源的利用率,提高数据库系统的事务吞吐量,从而可以支持更多用户。但是并发也会带来一些问题:

  • 丢失更新:多个事务同时对同一行数据更新,然后基于最初选定的值实施操作时,由于事务的隔离性使得互相并不知道对方的存在。从而造成最后的更新覆盖其他所有事务的更新。
  • 脏读:一个事务正在对一条记录做修改,在事务提交前,当前记录处于不稳定状态;这时另一个事务也来读取这条记录,如果不加控制,第二个事务可能会读取脏数据并产生对未提交数据的依赖。这种现象叫“脏读”。
  • 不可重复读:一个事务读取某些数据后的某个时间,再次尝试读取以前读过的数据,取发现数据已经被修改或删除。这种现象就叫做“不可重复读”。
  • 幻读:一个事务按照相同的条件查询之前检索过的记录,却发现有其它事务插入了新的数据。这种现象就称为“幻读”。

丢失更新不能完全依靠数据库事务控制器来解决,需要应用程序对需要更新的数据加必要的锁来解决。因此,防止丢失更新是应用程序的责任。从线程并发的角度来说,应该在可能更新数据的方法上进行同步。

数据库实现事务隔离的方式,基本上可分为两种:

一种是在读取数据前,对其加锁,阻止其它事务对数据进行修改。

另一种是不加任何锁,而是通过一定机制生成一个数据请求点的一致性数据快照,并用这个快照来提供一定级别的一致性读取操作。

数据库的事务隔离越严格,并发的副作用越小,但付出的代价就越大。因为事务隔离实质上就是使事务在一定程度上“序列化”,这显然与并发是相矛盾的。为了解决上述矛盾,MySQL定义了4种事务隔离级别,分别叫:未提交读取、已提交读取、可重复读取、可序列化。具体定义请参考上一篇文章,这里不赘述了。

二、InnoDB的行级锁模式

InnoDB提供了两种类型的行级锁和与之匹配的表级锁。

  • 行共享锁:允许其它事务的读取但阻止获取排他锁。
  • 行排他锁:允许当前事务读取和更新数据,但阻止其它事务取得操作数据集的行共享锁与行排他锁。
  • 表共享锁(意向共享锁):事务打算给数据行加行共享锁,需要先取得该数据表的表共享锁。
  • 表排他锁(意向排他锁):事务打算给数据行加行排他锁,需要先取得该数据表的表排他锁。

需要注意,当一个事务获得一个数据表的表排他锁时,另一个事务也可以获取这个数据表的排他锁。因为两个更新数据的事务彼此不会冲突,而丢失更新的问题应该交给应用层解决。由此可见,InnoDB对锁的实现显然比字面表述更加复杂。这就是为什么我们通常称InnoDB的表级锁为意向锁的原因,它和MyISAM的表级锁有根本性区别。

至于具体加锁的操作,不在本文的讨论范围。

三、MyISAM的表级锁模式

MyISAM引擎不支持事务,因此不存在所谓的事务并发问题。MyISAM的表级锁有两种模式:表共享读锁和表排他写锁。除了语义上的不同以外,与InnoDB的区别主要是以下两点:

  • MyISAM给表加锁是同时取得所有涉及表的锁,而InnoDB则是逐步获取锁。因此MyISAM不会出现死锁现象。反过来说,正是由于这个特点的存在,实际运行中写进程优先于读进程。因此MyISAM可能会出现读进程永远被阻塞的情况,InnoDB却不会遇到这样的问题。
  • 使用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的读操作不出现“幻读”问题。

时间: 2024-12-13 02:09:41

事务隔离级别(二)的相关文章

MySQL事务隔离级别详解

SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的.低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销.Read Uncommitted(读取未提交内容) 在该隔离级别,所有事务都可以看到其他未提交事务的执行结果.本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少.读取未提交的数据,也被称之为脏读(Dirty Read).Read Committed(读取提交内容) 这是大多数数据库系统的默认隔离级别(但不是MySQL默认的).

Innodb中的事务隔离级别和锁的关系

前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力.所以对于加锁的处理,可以说就是数据库对于事务处理的精髓所在.这里通过分析MySQL中InnoDB引擎的加锁机制,来抛砖引玉,让读者更好的理解,在事务处理中数据库到底做了什么. #一次封锁or两段锁? 因为有大量的并发访问,为了预防死锁,一般应用中推荐使用一次封锁法,就是在方法的开始阶段,已经预先知道

mysql-Innodb事务隔离级别-repeatable read详解

http://blog.csdn.net/dong976209075/article/details/8802778 经验总结: Python使用MySQLdb数据库后,如使用多线程,每个线程创建一个db链接,然后再各自创建一个游标cursor,其中第一个线程读一个表中数据为空,第二个写入该表一条数据并提交,第一个线程再读该表数据将仍然无法读出.和多数据库的事务级别应该有关系:还可以在第一个读之前先插入一条,将能够读出第二个线程写入并提交过的数据. 转载自:http://blog.csdn.ne

Innodb中的事务隔离级别和锁的关系(转)

原文:http://tech.meituan.com/innodb-lock.html 前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力.所以对于加锁的处理,可以说就是数据库对于事务处理的精髓所在.这里通过分析MySQL中InnoDB引擎的加锁机制,来抛砖引玉,让读者更好的理解,在事务处理中数据库到底做了什么. 一次封锁or两段锁? 因为有大量的并

数据库事务隔离级别-- 脏读、幻读、不可重复读

一.数据库事务隔离级别 数据库事务的隔离级别有4个,由低到高依次为Read uncommitted .Read committed .Repeatable read .Serializable ,这四个级别可以逐个解决脏读 .不可重复读 .幻读 这几类问题. √: 可能出现    ×: 不会出现   脏读 不可重复读 幻读 Read uncommitted √ √ √ Read committed × √ √ Repeatable read × × √ Serializable × × × 注意

MySQL InnoDB中的事务隔离级别和锁的关系

前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力.所以对于加锁的处理,可以说就是数据库对于事务处理的精髓所在.这里通过分析MySQL中InnoDB引擎的加锁机制,来抛砖引玉,让读者更好的理解,在事务处理中数据库到底做了什么. 一.一次封锁or两段锁因为有大量的并发访问,为了预防死锁,一般应用中推荐使用一次封锁法,就是在方法的开始阶段,已经预先知道会

数据库:自己理解的“数据库事务隔离级别”

转载请注明出处: jiq?钦's technical Blog - 季义钦 引言:在网上搜了很多关于事务的文章,感觉单独来看都很难看懂,所以综合自己的理解写一篇我自己能理解的关于关系型数据库事务的文章. 一.事务特征 我们都知道数据库事务具备ACID特性: Atomic(原子性):一个事务要么成功,要么失败 Consistency(一致性):一致性代表了底层数据存储的完整性.事务执行前后数据库都必须处于一个合法的状态.什么才是一个合法的状态? 比如满足数据库的唯一性约束.数据类型验证.引用完整性

SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因

原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中的事务概念,ACID 原则,事务中常见的问题,问题造成的原因和事务隔离级别等这些方面的知识好好的整理了一下. 其实有关 SQL Server 中的事务,说实话因为内容太多, 话题太广,稍微力度控制不好就超过了我目前知识能力范围,就不是三言两语能够讲清楚的.所以希望大家能够指出其中总结的不足之处,对我

数据库事务隔离级别(转)

1.什么是事务,事务的特性是什么? 在数据库中事务是工作的逻辑单元,一个事务是由一个或多个完成一组的相关行为的SQL语句组成,通过事务机制确保这一组SQL语句所作的操作要么都成功执行,完成整个工作单元操作,要么一个也不执行. SQL92标准定义了数据库事务的四个特点: 原子性(Atomicity):一个事务里面所有包含的SQL语句是一个执行整体,不可分割,要么都做,要么都不做. 一致性(Consistency):事务开始时,数据库中的数据是一致的,事务结束时,数据库的数据也应该是一致的. 隔离性