学了两天的hibernate锁机制今天写个总结 hibernate锁机制包括悲观锁和乐观锁 悲观锁 它指的是对数据被外界修改持保守态度假定任何时刻存取数据时都可能有另一个客户也正在 存取同一笔数据为了保持数据被操作的一致性于是对数据采取了数据库层次的锁定状态依靠数 据库提供的锁机制来实现 基于jdbc实现的数据库加锁如下 select*fromaccountwherename=Ericaforupdate在更新的过程中数据库处于加锁状 态任何其他的针对本条数据的操作都将被延迟本次事务提交后解锁 而hibernate悲观锁的具体实现如下 Stringsql=查询语句; Queryquery=sessioncreateQuery(sql); querysetLockMode(对象LockModelUPGRADE); 说到这里就提到了hiernate的加锁模式 LockModeNONE无锁机制 LockModeWRITEHibernate在Insert和Update记录的时候会自动获取 LockModeREADHibernate在读取记录的时候会自动获取 这三种加锁模式是供hibernate内部使用的与数据库加锁无关 LockModeUPGRADE利用数据库的forupdate字句加锁 在这里我们要注意的是只有在查询开始之前(也就是hiernate生成sql语句之前)加锁才会真 正通过数据库的锁机制加锁处理否则数据已经通过不包含forupdata子句的sql语句加载进来 所谓的数据库加锁也就无从谈起 但是从系统的性能上来考虑对于单机或小系统而言这并不成问题然而如果是在网络上的 系统同时间会有许多联机假设有数以百计或上千甚至更多的并发访问出现我们该怎么办?如果 等到数据库解锁我们再进行下面的操作我们浪费的资源是多少?这也就导致了乐观锁的产生 乐观锁乐观锁定(optimisticlocking)则乐观的认为资料的存取很少发生同时存取的问题因而不作数 据库层次上的锁定为了维护正确的数据乐观锁定采用应用程序上的逻辑实现版本控制的方法 例如若有两个客户端A客户先读取了账户余额元之后B客户也读取了账户余额元的数据 A客户提取了元对数据库作了变更此时数据库中的余额为元B客户也要提取元根据其所 取得的资料将为余额若此时再对数据库进行变更最后的余额就会不正确 在不实行悲观锁定策略的情况下数据不一致的情况一但发生有几个解决的方法一种是先更新 为主一种是后更新的为主比较复杂的就是检查发生变动的数据来实现或是检查所有属性来实现 乐观锁定 Hibernate中透过版本号检查来实现后更新为主这也是Hibernate所推荐的方式在数据库中加 入一个VERSON栏记录在读取数据时连同版本号一同读取并在更新数据时递增版本号然后比对版 本号与数据库中的版本号如果大于数据库中的版本号则予以更新否则就回报错误 以刚才的例子A客户读取账户余额元并连带读取版本号为的话B客户此时也读取账号余 额元版本号也为A客户在领款后账户余额为此时将版本号加版本号目前为而数 据库中版本号为所以予以更新更新数据库后数据库此时余额为版本号为B客户领款后 要变更数据库其版本号为但是数据库的版本号为此时不予更新B客户数据重新读取数据库 中新的数据并重新进行业务流程才变更数据库 以Hibernate实现版本号控制锁定的话我们的对象中增加一个version属性例如 publicclassAccount{ privateintversion;
publicvoidsetVersion(intversion){ thisversion=version; } publicintgetVersion(){ returnversion; }
} 而在映像文件中我们使用optimisticlock属性设定version控制<id>属性栏之后增加一个 <version>标签如下 <hibernatemapping> <classname=onlyfuncaterpillarAccounttalble=ACCOUNT optimisticlock=version> <id/> <versionname=versioncolumn=VERSION/>
</class> </hibernatemapping> 设定好版本控制之后在上例中如果B客户试图更新数据将会引发StableObjectStateException 例外我们可以捕捉这个例外在处理中重新读取数据库中的数据同时将B客户目前的数据与数据 库中的数据秀出来让B客户有机会比对不一致的数据以决定要变更的部份或者您可以设计程式 自动读取新的资料并重复扣款业务流程直到数据可以更新为止这一切可以在背景执行而不用 让您的客户知道 但是乐观锁也有不能解决的问题存在上面已经提到过乐观锁机制的实现往往基于系统中的数据 存储逻辑在我们的系统中实现来自外部系统的用户余额更新不受我们系统的控制有可能造成非 法数据被更新至数据库因此我们在做电子商务的时候一定要小心的注意这项存在的问题采用比 较合理的逻辑验证避免数据执行错误 也可以在使用Session的load()或是lock()时指定锁定模式以进行锁定 如果数据库不支持所指定的锁定模式Hibernate会选择一个合适的锁定替换而不是丢出一个例外 |