日期:2014-05-16  浏览次数:20454 次

Hibernate之事务、隔离级别、悲观锁、乐观锁

事务需要保证原子性(Atomicity)、一致性(Consistence)、隔离性(Isolation behavior)、持续性(Durability),简称ACID。

原子性:一个事务内的操作要么全部成功,要么全部失败回滚。

一致性:事务内的数据,如果事务成功,则必须都是成功后的状态,如果失败,则必须都是最开始的状态,不能有的是成功后的状态,有的是开始的状态。

隔离性:在多个事务同时进行的情况下,互相不能干扰。

持续性:事务一旦成功,则事务成功的结果必须保存下来。

事务可以由声明式事务和编程式事务,声明式的事务由容器所提供的服务,可以在配置文件中定义事务边界、隔离级别等。

编程式事务是直接使用JDBC或者相关框架的API,以编写代码的方式,可以更细致的定义事务边界、隔离级别等。

?

下面重点介绍下事务的隔离性怎么保证。

在数据库中保证隔离性最基本的方式就是锁定数据库,或者被更新、读取的表、列,如果数据库不锁定数据会发生的事:

1.lost update

事务A更新某条数据

事务B更新某条数据

事务B commit

事务A commit

事务A的更新就丢失了。

?

2.dirty read

事务A更新某条数据

事务B读取该条数据

事务A commit

事务B commit

这种情况下事务B读的就是脏数据。

?

3.unrepeatable read

事务A读取某条数据

事务B更新了数据

事务B commit

事务A再次读取数据

这时A两次读取的结果就不一样

?

4.phantom read

事务A查询到了5条数据

事务B更新了相关联的表

事务B commit

事务A再次查询只得到了4条数据

这次事务A就是幻读了

?

为了解决上面的4种问题,就出现了4种隔离级别,不同的数据库默认使用不同的隔离级别

1.read uncommit

当事务A更新某条数据时,不容许其他事务来更新该数据,但可以读取。

?

2.read commit

当事务A更新某条数据时,不容许其他事务进行任何操作包括读取,但事务A读取时,其他事务可以进行读取、更新

?

3.read repeatable

当事务A更新数据时,不容许其他事务进行任何操作,但当事务A进行读取时,其他事务只能读取,不能更新。

?

4.serializable

最严格的隔离级别,事务必须依次进行。

?

Hibernate乐观锁策略,认为很少出现同时读取、更新的情况,在数据库隔离级别一般设为read commit,会导致出现lost update的问题

对于lost update问题,有3种解决策略:

先更新为主:两个事务同时更新,但后提交的事务将抛出exception,后面的事务必须重新获取数据

后更新为主:后提交的事务直接覆盖先提交的。

合并冲突:后提交的数据会得到提示,只更新没有冲突的列

Hibernate推荐我们使用先更新为主,是通过version来实现的,即读取数据的时候会得到一个version值,提交时会将这个version值和数据库中的相比,如果一样则证明可以成功提交,并同时将version+1。

实现version可以在对象模型中加一个version属性,并在关系模型加一个version列,也可以配置让hibernate通过比较对象所有的属性来确实是否是可以更新。

Hibernate悲观锁策略,认为会经常出现同时读取、更新的情况;

List users1 = query.list();
query.setLockMode("user", LockMode.UPGRADE);

hibernate通过锁定数据来避免lost update的问题。

<script type="text/javascript"></script>