深入浅出事务之隔离级别

除了事务传播属性(可参考我的另一篇文章《深入浅出事务之传播属性》)之外,另一个需要开发人员关注的是事务的隔离级别,它决定了一个事务中所进行的更新操作对其它事务的可见性。事实上,DBMS、EJB、Spring都允许你设置不同的隔离级别,你必须保证它们相互统一、兼容;因此,应用服务器可能支持许多种隔离级别,但要使用其中的某一种,首先你必须保证你的数据库也支持它。

事务的隔离性实质上是数据库的并发性与一致性的函数。随着事务隔离级别的上升,数据库的一致性随之上升,而并发性反而下降。事务隔离的这种特性实际上会影响一个应用的性能和数据完整性,例如,对于性能要求较高的应用比如信用卡处理等,您可以适当降低其事务隔离级别,以提高整个应用的并发性(但是会降低数据的完整性);对于并发量较小的应用比如财务处理等,您可以适当提高其事务隔离级别,以提高数据的完整性(但是会降低应用的性能)。大多数应用服务器和数据库都有自己默认的事务隔离级别,当然,通过Spring或EJB您可以很方便地修改。

Spring和EJB都支持四种基本的事务隔离级别,它们是(隔离级别从低到高的顺序):
[list]
[*]读未提交(TransactionReadUncommited)
[*]读已提交(TransactionReadCommited)
[*]可重复读(TransactionRepeatableRead)
[*]串行化(TransactionSerializable)
[/list]

[b]6.2.1、读未提交[/b]
这是Spring所支持的最低的隔离级别,在该隔离级别下,事务允许在其它事务提交之前,读取其未提交的、对数据库的任何修改。为了说明这个问题,我们还是以在线交易为例,假设当前的价格为90.00,此时,有两个事务同时到达,事务A执行更新操作,而事务B执行查询操作;在事务隔离级别设置为“读未提交”时,该场景的处理流程如下图所示:

[align=center][img]http://dl.iteye.com/upload/attachment/378729/abb94ad1-e704-33c5-962e-47e0a680aee7.jpg[/img][/align]]

注意,在t2时刻,事务A对数据库进行了一次更新操作,而它提交之前,事务B就可以在t3时刻观察到这种变化,读取到更新后的价格(94.23);也就是说,事务A中的更新操作完全没有被隔离。如果事务A因为异常回滚,那么事务B中读取的数据就是脏数据。这一隔离级别违反了最基本的ACID特性,因此很多数据库都不支持(包括Oracle) 。

[b]6.2.2、读已提交[/b]
这一隔离级别允许多个事务同时操作一组数据,但是隐藏了事务之间所有未提交的更新;即事务A看不见事务B中对数据库所作的修改,直到事务B提交为止。仍然以上面的在线交易为例,此时的处理流程如下图所示:

[align=center][img]http://dl.iteye.com/upload/attachment/378731/ab227fb8-3089-3a14-ad62-9d18e3d4633f.jpg[/img][/align]

注意,当事务A在t2时刻更新了价格(94.23)之后,事务B在t3时刻仍然看不到该更新,此时读取价格仍然是90.00。这是一种是用较多的隔离级别,它既允许了事务B获取数据(支持并发性),同时又隐藏了其它事务(事务A)对该数据的更新,直到(事务A)提交的那一刻为止。几乎所有的数据库都支持“读已提交”的隔离级别,并且大部分将其作为缺省的隔离级别。

[b]6.2.3、可重复读[/b]
这是较之前两者更为严格的事务隔离级别,它真正将所有事物相互隔离起来。该隔离级别确保,事务开始时读取到的一组数据,在整个事务周期内都不会改变(除非拥有读写锁的事务本身修改了它),直到该事务提交为止。仍然以上面的在线交易为例,此时的处理流程如下图所示:

[align=center][img]http://dl.iteye.com/upload/attachment/378733/65f5b849-1126-375b-80a7-5f245fa29c39.jpg[/img][/align]

注意在这个例子中,尽管在事务B执行期间,事务A插入了一条数据(QRS),但是在事务B在t2时刻查询所得的结果依然和t0时刻一样(不包含QRS),即使到了t4时刻,事务A已经提交了也是如此(这一点不同于“读已提交”) 。只有在事务B也提交了,它才会看见事务A对数据库所作的修改。值得注意的是,该隔离级别下,会在被查询或修改的数据上加上读写锁,因此任何想要修改该数据的其它事务会等待(或失败),直到“可重复读”的事务提交为止。

[b]6.2.4、串行化[/b]
这是JAVA所支持的最高隔离级别。在该隔离级别下,所有同时到达的事务将会“排队进入”,保证每次只允许一个事务操作数据。(我们后面将会看到,对于Oracle来说,这并不完全正确) 。使用“串行化”的隔离级别,应用的并发性明显下降,而数据完整性则显著提高。仍然以上面的在线交易为例,此时的处理流程如下图所示:

[align=center][img]http://dl.iteye.com/upload/attachment/378735/7fd2ad9f-dfb0-3c2d-ad9b-acd2c14bf2cf.jpg[/img][/align]

此时,事务B将会一直挂起,直到事务A提交(或回滚) 。尽管所有的数据库都支持这种隔离级别,Oracle的处理方式略有不同,它使用“多版本数据“的方式来避免事务B的挂起。但是,如果事务B试图获取事务A所处理的数据时,Oracle会抛出ORA08177的错误信息,提示该事务隔离级别下,无法串行获取数据。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值