在使用Hibernate的过程中,我们会遇到多人对同一个数据同时进行修改,这个时候就会产生脏数据,造成数据的不一致性。为了避免更新数据的丢失,Hibernate采用了锁的机制。
Hibernate提供了两种锁的机制:悲观锁和乐观锁
悲观锁:在数据有加载的时候就给其进行加锁,直到该锁被释放掉,其他用户才可以进行修改;
乐观锁:在对数据进行修改的时候,对数据采用版本号或者时间戳等方式来比较,数据是否一致性来实现加锁;
一、悲观锁
悲观锁是依靠数据库提供的锁机制。Hibernate是通过使用数据库的for update子句实现了悲观锁机制。
Hibernate有如下五种加锁机制
1、 LockMode.NONE:无锁机制;
2、 LockMode.WRITE:Hibernate在Insert和Update记录的时候会自动获取
3、 LockMode.READ:Hibernate在读取记录的时候会自动获取
4、 LockMode.UPGRADE:利用数据库的for update子句加锁
5、 LockMode.UPGRADE_NOWAIT:Oracle的特定实现,利用Oracle的for update nowait子句实现加锁
悲观加锁一般通过以下三种方法实现:
1、Criteria.setLockMode
2、Query.setLockMode
3、Session.lock
public void query(int id){ Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); String hql = "from Users as u where id= :id"; List list = session.createQuery(hql) .setLockMode("u", LockMode.UPGRADE) //执行加锁 .setInteger("id", id) .list(); for(Iterator iterator = list.iterator();iterator.hasNext();){ Users users = (Users) iterator.next(); System.out.println(users.getBirthday()); } }
select users0_.id as id0_, users0_.ver as ver0_, users0_.birthday as birthday0_, users0_.first_name as first4_0_, users0_.last_name as last5_0_ from Users users0_ with (updlock, rowlock) where users0_.id=?
悲观锁在对数据进行加锁后,会一直“霸占”该数据,直到释放掉,其他用户才可以对该数据进行更新。这里就存在一个问题,如果它一直占着不放,那么其他用户永远也不可能对该数据进行更新,这样就很不利于并发了。对于这个问题的解决方案,可以利用乐观锁。
二、乐观锁
乐观锁大多是基于数据版本记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
我们可以通过class描述符的optimistic-lock属性结合version描述符指定乐观锁。
1. none:无乐观锁
2. version:通过版本机制实现乐观锁
3. dirty:通过检查发生变动过的属性实现乐观锁
4. all:通过检查所有属性实现乐观锁
在实现乐观锁的持久化类我们需要为该持久化类增加一个version属性,并且提供相应的getter和setter方法。如下
public class Users { private int id; private Date birthday; private Name name; private int version; //舍掉getter和setter方法 }
<hibernate-mapping package="com.hibernate.domain"> <class name="Users" optimistic-lock="version"> <id name="id"> <generator class="native" /> </id> <version name="version" /> <property name="birthday" /> <!-- 映射组件元素 --> <component name="name"> <!-- 映射组件的name属性指向包含实体 --> <property name="firstName" column="first_name"/> <property name="lastName" column="last_name"/> </component> </class> </hibernate-mapping>
注意:version 节点必须出现在ID 节点之后。
在这里我们声明了一个version属性,该属性用于存放用户的版本信息。我们对user表每一次更新操作,都会引起version属性的变化:加1。如果我们尝试在tx.commit 之前,启动另外一个Session,对名为同一个用户进行操作,就是并发更新的情形了:
public void update(){ //开启事务tx1 Session session1 = HibernateUtil.getSession(); Transaction tx1 = session1.beginTransaction(); Users users1 = (Users) session1.get(Users.class, 1); //获取id为1的用户 //开启事务tx2 Session session2 = HibernateUtil.getSession(); Transaction tx2 = session2.beginTransaction(); Users users2 = (Users) session2.get(Users.class, 1); //获取id为1的用户 users1.getName().setFirstName("first name1"); users2.getName().setFirstName("first name2"); tx1.commit(); //..........1 tx2.commit(); //..........2 session1.close(); session2.clear(); }
执行以上代码,代码将在.....2处抛出StaleObjectStateException异常,并指出版本检查失败。
在这里是先提交者成功,后提交者失败。当前事务正在试图提交一个过期数据。通过捕捉这个异常,我们就可以在乐观锁校验失败时进行相应处理。
相关推荐
解压后,`mongo-cxx-driver-r3.6.2`目录下有头文件、源文件和示例代码,可以帮助理解和使用驱动程序。 在`MongoDBClientTest`目录中,包含了一个测试工程,这个工程展示了如何使用编译好的驱动程序连接到MongoDB...
apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-zookeeper-3.6.2-bin.tar apache-...
总之,`apache-maven-3.6.2-bin.zip` 提供了一个完整的Maven运行环境,让用户可以轻松地进行Java项目的构建和管理。通过其强大的依赖管理和标准化的构建流程,Maven已成为Java开发中不可或缺的工具之一。
总之,`apache-maven-3.6.2-bin.tar.gz`提供了Java项目管理和构建的强大工具,通过解压、配置环境变量以及编写和管理POM,开发者能够高效地处理复杂的项目依赖和构建流程。Maven 3.6.2版本修复了一些已知问题,提高...
本资源集合包含`hibernate-distribution-3.6.2`版本的API中文文档以及相关的jar包,旨在帮助开发者更好地理解和使用Hibernate框架。 首先,`hibernate-reference.pdf`是Hibernate 3.6.2的中文参考手册。这份PDF文档...
赠送jar包:rocketmq-client-3.6.2.Final.jar; 赠送原API文档:rocketmq-client-3.6.2.Final-javadoc.jar; 赠送源代码:rocketmq-...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。
总之,`hibernate-distribution-3.6.2.Final-dist`源码包是学习和研究Hibernate的好资料,通过深入研究源代码,开发者不仅可以掌握ORM的基本原理,还能提升对Java和数据库设计的理解,为开发更高效、更稳定的应用...
- 解压 `apache-zookeeper-3.6.2-bin.tar.gz` 压缩包后,你会得到 ZooKeeper 的二进制文件夹,包含配置文件、可执行程序和日志目录等。 - 配置文件 `conf/zoo.cfg` 是ZooKeeper的核心配置,需要根据实际环境进行...
总的来说,Apache Maven 3.6.2是一个强大且易用的项目管理工具,它通过标准化的构建过程和自动化依赖管理,极大地提高了开发效率,减少了项目维护的复杂性。无论你是个人开发者还是大型团队的一员,Maven都能成为你...
Maven 3.6.2是Maven的一个特定版本,它包含了各种改进和修复,以提供更稳定和高效的构建环境。 在"apache-maven-3.6.2.zip"这个压缩包中,用户可以获得Maven 3.6.2的完整安装包。这个版本包括了阿里云镜像配置,这...
赠送jar包:rocketmq-client-3.6.2.Final.jar; 赠送原API文档:rocketmq-client-3.6.2.Final-javadoc....人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。 双语对照,边学技术、边学英语。
在这个“apache-maven-3.6.2-bin”安装包中,包含了运行Maven所需的所有核心组件、插件和文档。 1. **Maven的基本概念**: Maven是基于项目对象模型(Project Object Model, POM)的概念,通过XML文件定义项目的...
v3.6.2 更新日志: 1.修复文件md5显示错误 2.修复无法上传 3.修复分享列表获取不到密码 4.更新上传、下载处理流程,优化重试的判断条件 5.更新download命令, 移除之前的-stream -share -locate等参数,新增-mode参数,...
总的来说,ksoap2-android-assembly-3.6.2-jar-with-dependencies是Android开发者与远程Web服务交互的强大工具,它的易用性和全面的功能使得处理复杂的SOAP通信变得更加简单。通过熟练掌握这个库的使用,开发者可以...
kSOAP2-android 3.6.2是这个库的一个特定版本,它包含了对Android平台的优化和适配。这个版本可能包含了一些新特性、性能改进或者错误修复,以提供更好的稳定性和兼容性。更新到这个版本,开发者可以确保他们的应用...
eclipse-sourceBuild-srcIncluded-3.6.2
3.6.2版本是lucene的3x中最大的版本,也是3x中最稳定的版本,因此建设使用该版本。如果还是使用3.6.0或3.6.1,更要升级到该版本...想下载源码包的,可以搜索源码包lucene-core-3.6.2-src.jar及lucene-queries-3.6.2.jar
apache-solr-3.6.2.zipapache-solr-3.6.2.zipapache-solr-3.6.2.zipapache-solr-3.6.2.zipapache-solr-3.6.2.zipapache-solr-3.6.2.zipapache-solr-3.6.2.zip
CKEditor 3.6.2是该编辑器的一个特定版本,它在前一版本的基础上进行了优化和改进,以提升用户体验和功能。 CKEditor的主要特点包括: 1. **丰富的编辑功能**:CKEditor支持多种文本格式处理,如字体、字号、颜色...