>데이터 베이스 >MySQL 튜토리얼 >hibernate中的乐观锁和悲观锁

hibernate中的乐观锁和悲观锁

WBOY
WBOY원래의
2016-06-07 14:50:591395검색

hibernate支持两种锁:悲观锁(Pessimistic Locking)和乐观锁(Optimistic Locking) 悲观锁:指的是对数据库数据被外界的修改持保守态度(无论是本系统的事务处理,或者是外部系统的事务处理),在整个数据处理的过程数据都处于锁定的状态。hibernate中的

hibernate支持两种锁:悲观锁(Pessimistic Locking)和乐观锁(Optimistic Locking)

悲观锁:指的是对数据库数据被外界的修改持保守态度(无论是本系统的事务处理,或者是外部系统的事务处理),在整个数据处理的过程数据都处于锁定的状态。hibernate中的悲观锁,是依靠数据库中的锁机制(因为只有数据库层才能控制本系统和外部系统对数据库的数据操作)。

例如”select * from user where userName=’Johnson’ for update“这条sql锁定了user表中所有userName=’Johnson’的记录,本次事务提交之前,外界无法修改这些记录。

hibernate中的悲观锁,也是基于数据库的锁机制实现的。

<code class=" hljs lasso"><span class="hljs-built_in">String</span> hqlStr <span class="hljs-subst">=</span><span class="hljs-string">"from TUser as user where user.name='Lili'"</span>;
Query query <span class="hljs-subst">=</span> session<span class="hljs-built_in">.</span>createQuery(hqlStr);
query<span class="hljs-built_in">.</span>setLockMode(<span class="hljs-string">"user"</span>,LockMode<span class="hljs-built_in">.</span>UPGRADE); <span class="hljs-comment">//加锁</span>
<span class="hljs-built_in">List</span> userList <span class="hljs-subst">=</span> query<span class="hljs-built_in">.</span><span class="hljs-built_in">list</span>();<span class="hljs-comment">//执行查询,获取数据</span></code>

上面的代码中setLockMode第一个参数指定了别名为user的返回的记录进行上锁。
生成的sql为:

<code class=" hljs applescript">select tuser0_.<span class="hljs-property">id</span> <span class="hljs-keyword">as</span> <span class="hljs-property">id</span>, tuser0_.<span class="hljs-property">name</span> <span class="hljs-keyword">as</span> <span class="hljs-property">name</span>, tuser0_.group_id
<span class="hljs-keyword">as</span> group_id, tuser0_.user_type <span class="hljs-keyword">as</span> user_type, tuser0_.sex <span class="hljs-keyword">as</span> sex
<span class="hljs-keyword">from</span> t_user tuser0_ <span class="hljs-keyword">where</span> (tuser0_.<span class="hljs-property">name</span>='Erica' ) <span class="hljs-keyword">for</span> update</code>

可见hibernate通过数据库中的for update子句实现悲观锁机制。
hibernate的加锁模式:
LockMode.NONE : 无锁机制。
LockMode.WRITE : Hibernate 在 Insert 和 Update 记录的时候会自动获取。
LockMode.READ : Hibernate 在读取记录的时候会自动获取。
以上这三种锁机制一般由 Hibernate 内部使用,如 Hibernate 为了保证 Update过程中对象不会被外界修改,会在 save 方法实现中自动为目标对象加上 WRITE 锁。
LockMode.UPGRADE :利用数据库的 for update 子句加锁。
LockMode. UPGRADE_NOWAIT : Oracle 的特定实现,利用 Oracle 的 for update nowait 子句实现加锁。
上面这两种锁机制是我们在应用层较为常用的,加锁一般通过以下方法实现:
Criteria.setLockMode
Query.setLockMode
Session.lock

相对于悲观锁,乐观锁的锁机制就显得比较宽松。悲观锁大部分情况依靠数据库的锁机制实现,来保证最大程度的独占性。但另一方面数据库的开销非常大,尤其对于长事务来说。

乐观锁大部分是基于数据版本(version)记录机制实现。即在数据表中增加一个版本标识,读取出数据时,连带这个版本标识一起读出,更新数据的时候,把版本标识加1。将提交版本数据跟数据库中当前版本信息对比,如果提交的数据中版本号大于数据表当前的版本号,则允许更新,否则认为是过期数据。

hibernate的乐观锁主要有两种方式:version和时间戳

举个配置的例子:

<code class=" hljs xml">    <span class="hljs-pi"><?xml version="1.0"?></span>  
    <span class="hljs-doctype"><!DOCTYPE hibernate-mapping PUBLIC  
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
            "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"></span>  
    <span class="hljs-tag"><<span class="hljs-title">hibernate-mapping</span>></span>  
        <span class="hljs-tag"><<span class="hljs-title">class</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"test.Dir"</span> <span class="hljs-attribute">table</span>=<span class="hljs-value">"t_dir"</span>></span>  
            <span class="hljs-tag"><<span class="hljs-title">id</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"id"</span> <span class="hljs-attribute">type</span>=<span class="hljs-value">"string"</span> <span class="hljs-attribute">unsaved-value</span>=<span class="hljs-value">"null"</span>></span>  
             <span class="hljs-tag"><<span class="hljs-title">column</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"id_"</span> <span class="hljs-attribute">sql-type</span>=<span class="hljs-value">"char(32)"</span> <span class="hljs-attribute">not-null</span>=<span class="hljs-value">"true"</span> /></span>  
             <span class="hljs-tag"><<span class="hljs-title">generator</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"uuid.hex"</span> /></span>  
        <span class="hljs-tag"></<span class="hljs-title">id</span>></span>  
        <span class="hljs-comment"><!--这里version节点必须要配在id之后--></span>
            <span class="hljs-tag"><<span class="hljs-title">version</span> <span class="hljs-attribute">column</span>=<span class="hljs-value">"version_"</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"version"</span> /></span>  
            <span class="hljs-tag"><<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"name"</span> <span class="hljs-attribute">column</span>=<span class="hljs-value">"name_"</span> <span class="hljs-attribute">type</span>=<span class="hljs-value">"string"</span>/></span>  
            <span class="hljs-tag"><<span class="hljs-title">property</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"size"</span> <span class="hljs-attribute">column</span>=<span class="hljs-value">"size_"</span> <span class="hljs-attribute">type</span>=<span class="hljs-value">"long"</span> /></span>  
            <span class="hljs-tag"><<span class="hljs-title">many-to-one</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"dir"</span> <span class="hljs-attribute">column</span>=<span class="hljs-value">"pid_"</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"test.Dir"</span> /></span>  
        <span class="hljs-tag"></<span class="hljs-title">class</span>></span>  
    <span class="hljs-tag"></<span class="hljs-title">hibernate-mapping</span>></span>  </code>

乐观锁带来的负面问题:如果两个不同的事务同时读取一条数据并进行更新时,程序会报异常:org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)。这时候就要捕获异常,然后处理并提醒用户再次提交。
同样,乐观锁也有局限性。就是只控制了本系统的事务并发操作,而外部系统对数据表的操作却无法控制,此时有个解决办法就是:在存储过程里实现乐观锁机制,这样无论是本系统或是外部系统的事务操作,数据库都可以控制。所以,在设计阶段,尽量考虑到各种情况,究竟是在程序端实现好,还是数据库端实现比较好。

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
이전 기사:redis 下载安装다음 기사:HQL查询语句