日期:2014-05-16 浏览次数:20475 次
事务需要保证原子性(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>