通过在表中及POJO中增加一个version字段来表示记录的版本,来达到多用户同时更改一条数据的冲突
数据库脚本:
createtablestudentVersion(idvarchar(32),namevarchar(32),verint);
POJO
packageVersion;
publicclassStudent{
privateStringid;
privateStringname;
privateintversion;
publicStringgetId(){
returnid;
}
publicvoidsetId(Stringid){
this.id=id;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicintgetVersion(){
returnversion;
}
publicvoidsetVersion(intversion){
this.version=version;
}
}
Student.hbm.xml
<?xmlversion="1.0"encoding="utf-8"?>
<!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
MappingfileautogeneratedbyMyEclipse-HibernateTools
-->
<hibernate-mapping>
<classname="Version.Student"table="studentVersion">
<idname="id"unsaved-value="null">
<generatorclass="uuid.hex"></generator>
</id>
<!--version标签必须跟在id标签后面-->
<versionname="version"column="ver"type="int"></version>
<propertyname="name"type="string"column="name"></property>
</class>
</hibernate-mapping>
Hibernate.cfg.xml
<?xmlversion='1.0'encoding='UTF-8'?>
<!DOCTYPEhibernate-configurationPUBLIC
"-//Hibernate/HibernateConfigurationDTD3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!--GeneratedbyMyEclipseHibernateTools.-->
<hibernate-configuration>
<session-factory>
<propertyname="connection.username">root</property>
<propertyname="connection.url">
jdbc:mysql://localhost:3306/schoolproject?characterEncoding=gb2312&useUnicode=true
</property>
<propertyname="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<propertyname="myeclipse.connection.profile">mysql</property>
<propertyname="connection.password">1234</property>
<propertyname="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<propertyname="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<propertyname="hibernate.show_sql">true</property>
<propertyname="current_session_context_class">thread</property>
<propertyname="jdbc.batch_size">15</property>
<mappingresource="Version/Student.hbm.xml"/>
</session-factory>
</hibernate-configuration>
测试代码:
packageVersion;
importjava.io.File;
importjava.util.Iterator;
importjava.util.Set;
importorg.hibernate.Session;
importorg.hibernate.SessionFactory;
importorg.hibernate.Transaction;
importorg.hibernate.cfg.Configuration;
publicclassTest{
publicstaticvoidmain(String[]args){
StringfilePath=System.getProperty("user.dir")+File.separator+"src/Version"+File.separator+"hibernate.cfg.xml";
Filefile=newFile(filePath);
System.out.println(filePath);
SessionFactorysessionFactory=newConfiguration().configure(file).buildSessionFactory();
Sessionsession=sessionFactory.openSession();
Transactiont=session.beginTransaction();
Studentstu=newStudent();
stu.setName("tom11");
session.save(stu);
t.commit();
/*
*模拟多个session操作student数据表
*/
Sessionsession1=sessionFactory.openSession();
Sessionsession2=sessionFactory.openSession();
Studentstu1=(Student)session1.createQuery("fromStudentswheres.name='tom11'").uniqueResult();
Studentstu2=(Student)session2.createQuery("fromStudentswheres.name='tom11'").uniqueResult();
//这时候,两个版本号是相同的
System.out.println("v1="+stu1.getVersion()+"--v2="+stu2.getVersion());
Transactiontx1=session1.beginTransaction();
stu1.setName("session1");
tx1.commit();
//这时候,两个版本号是不同的,其中一个的版本号递增了
System.out.println("v1="+stu1.getVersion()+"--v2="+stu2.getVersion());
Transactiontx2=session2.beginTransaction();
stu2.setName("session2");
tx2.commit();
}
}
运行结果:
Hibernate: insert into studentVersion (ver, name, id) values (?, ?, ?)
Hibernate: select student0_.id as id0_, student0_.ver as ver0_, student0_.name as name0_ from studentVersion student0_ where student0_.name='tom11'
Hibernate: select student0_.id as id0_, student0_.ver as ver0_, student0_.name as name0_ from studentVersion student0_ where student0_.name='tom11'
v1=0--v2=0
Hibernate: update studentVersion set ver=?, name=? where id=? and ver=?
v1=1--v2=0
Hibernate: update studentVersion set ver=?, name=? where id=? and ver=?
Exception in thread "main" org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Version.Student#4028818316cd6b460116cd6b50830001]
可 以看到,第二个“用户”session2修改数据时候,记录的版本号已经被session1更新过了,所以抛出了红色的异常,我们可以在实际应用中处理这 个异常,例如在处理中重新读取数据库中的数据,同时将目前的数据与数据库中的数据展示出来,让使用者有机会比较一下,或者设计程序自动读取新的数据
注意:如果手工设置stu.setVersion()自行更新版本以跳过检查,则这种乐观锁就会失效,应对方法可以将Student.java的setVersion设置成private
分享到:
相关推荐
2. **Hibernate的乐观锁机制**:了解Hibernate如何通过`version`字段实现乐观锁,包括`@Version`注解的使用、对象状态管理及冲突检测。 3. **乐观锁与悲观锁的区别**:对比两种锁的优缺点,例如悲观锁的资源消耗大...
在Hibernate中,乐观锁通常通过版本字段(version)或者时间戳(timestamp)实现: 1. **Version字段**:每个记录都有一个版本号字段,每次更新时会自动递增。如果更新时发现版本号与数据库中的不一致,那么更新...
Hibernate通过版本字段(Version)实现乐观锁,具体步骤如下: 1. 在实体类的`class`标签中添加`optimistic-lock="version"`属性,表示启用乐观锁。 2. 在`hibernate.cfg.xml`或`entity.hbm.xml`中,紧随`id`标签后...
**Hibernate**作为一种流行的Java持久层框架,提供了多种机制来处理并发控制问题,其中最常用的就是**乐观锁**和**悲观锁**。本文将详细介绍这两种锁的原理、应用场景以及如何在Hibernate中实现。 #### 二、悲观锁...
在Hibernate中,通常通过在实体类的映射文件中设置`optimistic-lock`属性来实现乐观锁,比如设置为`version`,这将利用数据库的版本字段来检测并发冲突。当尝试更新时,如果发现版本号已变,说明有其他事务进行了...
本文将深入探讨 Hibernate 版本的乐观锁机制,特别是通过XML配置方式实现这一机制。乐观锁是一种非阻塞锁,它假设在并发环境下数据冲突的概率较低,因此在读取数据时不加锁,而在更新数据时检查在此期间是否有其他...
Hibernate 中的乐观锁实现方式可以通过在对象中增加一个 version 属性来实现版本号控制锁定。例如: ```java public class Account { private int version; .... public void setVersion(int version) { this....
**Hibernate中的乐观锁实现**: 在Hibernate中,可以通过配置文件或注解的方式指定实体类的乐观锁策略。例如,使用版本号字段: ```java @Entity @Table(name = "account") public class Account { @Id @...
Hibernate乐观锁是数据库事务控制的一种策略,主要用于处理并发更新数据的情况。在乐观锁的机制下,假设并发用户很少会发生冲突,所以在读取数据时不会进行任何锁定,而在更新数据时才会检查在此期间是否有其他用户...
总结来说,Hibernate的悲观锁和乐观锁是两种不同的并发控制策略,悲观锁倾向于预防并发冲突,适合并发较低但需要保证数据一致性的情景;而乐观锁则在并发较高的情况下更优,通过版本控制减少锁定,但在冲突处理上...
在Hibernate中,可以使用`@Version`注解来实现乐观锁。每次更新实体时,Hibernate会检查版本号是否匹配。如果版本不匹配,更新会被回滚,从而防止丢失更新。 ```java @Entity @org.hibernate.annotations.Cache...
在Java的持久化框架Hibernate中,悲观锁和乐观锁是两种重要的并发控制策略,它们用于管理数据库中的数据在多线程环境下的访问安全。本文将深入探讨这两种锁机制的原理、应用场景及其区别。 首先,我们来理解悲观锁...
在Hibernate中,可以使用`@Version`注解来实现乐观锁,该注解会在实体类的一个属性上添加版本字段,每次更新时,Hibernate会比较当前版本号和数据库中的版本号,如果不同,则认为有并发冲突,更新失败。乐观锁的优点...
在Hibernate中,可以通过在实体类的属性上添加@Version注解来实现乐观锁。 悲观锁则是在数据读取时就立即加锁,直到事务结束才释放,确保了其他事务在此期间无法修改数据。Hibernate提供了LockMode类型的锁,如...
Hibernate提供了多种并发策略,如版本字段(version)和时间戳(timestamp),以实现乐观锁。在更新数据时,Hibernate会检查版本号或时间戳,如果发现有其他事务在此期间也修改了数据,就会抛出并发异常,从而避免...
在这个例子中,`@Version`注解表示该字段用于实现乐观锁。当尝试更新记录时,Hibernate会检查版本号是否发生变化,如果发生变化则抛出异常。 **3. 乐观锁的优势与局限** - **优势**:乐观锁避免了长时间锁定数据的...
在Hibernate中,乐观锁通常通过版本号(Version)或时间戳(Timestamp)来实现。当多个事务尝试更新同一条记录时,如果某个事务的版本号与数据库中的不匹配,那么更新会被拒绝。这样可以避免锁竞争,提高并发性能,...
在Java的持久化框架Hibernate中,版本管理机制是实现事务并发控制的重要手段。它通过维护对象的版本信息,确保在多线程环境下数据的一致性和完整性。本文将深入探讨Hibernate中的版本管理机制及其在控制事务并发中的...
- Hibernate支持自动的乐观锁管理,通过@Entity注解的@Version字段,Hibernate会在提交时自动处理版本号比较和更新。 此外,还有其他的并发控制策略,如行级锁定、两阶段锁定、多版本并发控制(MVCC)等。在实际应用...