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的问题。

你可能感兴趣的:(数据库)