Hibernate锁机制的简单理解

来源:互联网 发布:淘宝里咸鱼怎么找 编辑:程序博客网 时间:2024/06/05 02:00

我们知道事务并发会引发一些问题,一个典型的例子就是银行存取款的问题:

比如一个账户,用户A和B同时对它操作。假设账户里有1000元,A要往里存100元,而B要取100元,

假设这两个事务同时进行,会出现什么情况那?

首先A的事务一查账户里有1000元,B事务在A事务没有提交前(或者说执行期间)查询数据库也是1000元,

这时没有任何问题,这时A的事务提交将数据改为1100元(1000+100),而B事务后提交将数据改为900元(1000-100),

最终结果就是900元,我们知道,正确的结果应该是1000元。当然如果B事务先提交,最终的结果也是不对的。


事务并发到底可能会引起那些后果呢?有如下几种情况:

①第一类丢失更新:撤消一个事务时,把其它事务已提交的更新的数据覆盖了。
②脏读:一个事务读到另一个事务未提交的更新数据。
③幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。
④不可重复读:一个事务两次读同一行数据,可是这两次读到的数据不一样。
⑤第二类丢失更新:这是不可重复读中的特例,一个事务覆盖另一个事务已提交的更新数据。

上面说的情况就是第四种,对于第一种情况,我们知道事务具有四个属性(ACID),只要数据库都支持,

事务之间是不可能交叉影响的,事务具有隔离性,所以不用考虑。对于第二种情况,一般情况下数据库

会有一个默认的隔离级别,通过锁来实现,也不会出现,比如oracle就不支持脏读。第三种情况,业务上很少

出现,比如你要进行一些查询,一般很少查了一遍,接着又查了一遍,即便是有这种情况也不会带来“异常”后果,

多出的数据肯定是有新的业务行为发生了,所以一般也不用处理这种问题。所以一般处理并发带来的问题就是指的第

④⑤中情况,简单说就是对于同一条数据,多个事务你改我也改,或者说你改着我读==。

为了解决多个事务并发会引发的问题。大多数数据库系统提供了四种事务隔离级别供用户选择。
Serializable:串行化。隔离级别最高
Repeatable Read:可重复读。
Read Committed:读已提交数据。
Read Uncommitted:读未提交数据。隔离级别最差。
数据库系统采用不同的锁类型来实现以上四种隔离级别,
具体的实现过程对用户是透明的,用户应该关心的是如何选择合适的隔离级别。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读,
而且具有较好的并发性能。(oracle的默认级别就是Read Committed)

 当数据库系统采用Red Committed隔离级别时,会导致不可重复读和第二类丢失更新的并发问题,
在可能出现这种问题的场合。可以在应用程序中采用悲观锁或乐观锁来避免这类问题。

乐观锁:乐观锁的原理极为简单

Hibernate中通过版本号检查来实现后更新为主,这也是Hibernate推荐的方式

说白了就是在数据表中多加一个字段Version,事务如果对数据进行了变更操作,就将准备的数据里的version+1;

然后去跟数据库里的版本比较,如果发现自己的Version不比数据库里的大(说明这个过程中别的事务将它+1了,

也可能是在update后的where条件加上version=旧值 的方式)就无法更新成功。


而悲观锁假定当前事务操纵数据资源时,假定肯定还会有其他事务同时访问该数据资源,

为了避免当前事务的操作受到干扰,先锁定资源,一直到事务执行完毕释放。

悲观锁往往是通过使用数据库的锁机制实现的,比如oracle中就是通过使用select for update的形式实现的。

悲观锁一直锁着资源,而如果此事务由于某些原因一致没有执行完,其他的事务只能一直等待,很能影响性能,

而乐观锁有点线程抢占cpu的思想,能很好的使用数据库资源。 所以应该慎重使用悲观锁。

两种锁机制具体的使用尚未涉及,目前处于学习阶段。 

0 0