通过在表中及POJO中增加一个version字段来表示记录的版本,来达到多用户同时更改一条数据的冲突
数据库脚本:
create table studentVersion (id varchar(32),name varchar(32),ver int); POJO
package Version;
public class Student ...{
private String id;
private String name;
private int version;
public String getId() ...{
return id;
}
public void setId(String id) ...{
this.id = id;
}
public String getName() ...{
return name;
}
public void setName(String name) ...{
this.name = name;
}
public int getVersion() ...{
return version;
}
public void setVersion(int version) ...{
this.version = version;
}
}
Student.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
<class name="Version.Student" table="studentVersion" >
<id name="id" unsaved-value="null">
<generator class="uuid.hex"></generator>
</id>
<!--version标签必须跟在id标签后面-->
<version name="version" column="ver" type="int"></version>
<property name="name" type="string" column="name"></property>
</class>
</hibernate-mapping>
Hibernate.cfg.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>
<session-factory>
<property name="connection.username">root</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/schoolproject?characterEncoding=gb2312&useUnicode=true
</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="myeclipse.connection.profile">mysql</property>
<property name="connection.password">1234</property>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.show_sql">true</property>
<property name="current_session_context_class">thread</property>
<property name="jdbc.batch_size">15</property>
<mapping resource="Version/Student.hbm.xml" />
</session-factory>
</hibernate-configuration>
测试代码:
package Version;
import java.io.File;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class Test ...{
public static void main(String[] args) ...{
String filePath=System.getProperty("user.dir")+File.separator+"src/Version"+File.separator+"hibernate.cfg.xml";
File file=new File(filePath);
System.out.println(filePath);
SessionFactory sessionFactory=new Configuration().configure(file).buildSessionFactory();
Session session=sessionFactory.openSession();
Transaction t=session.beginTransaction();
Student stu=new Student();
stu.setName("tom11");
session.save(stu);
t.commit();
/**//*
* 模拟多个session操作student数据表
*/
Session session1=sessionFactory.openSession();
Session session2=sessionFactory.openSession();
Student stu1=(Student)session1.createQuery("from Student s where s.name='tom11'").uniqueResult();
Student stu2=(Student)session2.createQuery("from Student s where s.name='tom11'").uniqueResult();
//这时候,两个版本号是相同的
System.out.println("v1="+stu1.getVersion()+"--v2="+stu2.getVersion());
Transaction tx1=session1.beginTransaction();
stu1.setName("session1");
tx1.commit();
//这时候,两个版本号是不同的,其中一个的版本号递增了
System.out.println("v1="+stu1.getVersion()+"--v2="+stu2.getVersion());
Transaction tx2=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
分享到:
相关推荐
【Hibernate乐观锁与悲观锁详解】 在开发过程中,尤其是在并发环境下,确保数据的一致性和完整性至关重要。Hibernate,作为Java领域广泛使用的ORM框架,提供了一种处理并发数据访问冲突的手段,那就是锁机制。主要...
在Hibernate中,乐观锁通常通过版本字段(version)或者时间戳(timestamp)实现: 1. **Version字段**:每个记录都有一个版本号字段,每次更新时会自动递增。如果更新时发现版本号与数据库中的不一致,那么更新...
Hibernate乐观锁是数据库事务控制的一种策略,主要用于处理并发更新数据的情况。在乐观锁的机制下,假设并发用户很少会发生冲突,所以在读取数据时不会进行任何锁定,而在更新数据时才会检查在此期间是否有其他用户...
在Hibernate中,通常通过在实体类的映射文件中设置`optimistic-lock`属性来实现乐观锁,比如设置为`version`,这将利用数据库的版本字段来检测并发冲突。当尝试更新时,如果发现版本号已变,说明有其他事务进行了...
在了解了Hibernate乐观锁的XML配置后,我们可以结合源码进一步分析其实现细节。在Hibernate中,乐观锁的处理主要在`org.hibernate.event.internal.DefaultMergeEventListener`和`org.hibernate.event.internal....
### Hibernate的乐观锁与悲观锁 #### 一、引言 在并发环境下,尤其是在金融、电商等业务场景中,确保数据的一致性和完整性至关重要。**Hibernate**作为一种流行的Java持久层框架,提供了多种机制来处理并发控制...
在Hibernate框架中,乐观锁的实现方式之一是通过`version`字段,也就是我们这个练习的主题。`version`字段通常是一个整数或时间戳,记录了数据的版本信息。每次数据更新时,Hibernate会自动将`version`字段加一或者...
**Hibernate中的乐观锁实现**: 在Hibernate中,可以通过配置文件或注解的方式指定实体类的乐观锁策略。例如,使用版本号字段: ```java @Entity @Table(name = "account") public class Account { @Id @...
Hibernate 中的乐观锁实现方式可以通过在对象中增加一个 version 属性来实现版本号控制锁定。例如: ```java public class Account { private int version; .... public void setVersion(int version) { this....
Hibernate推荐的乐观锁实现是通过在实体类中添加一个版本字段,每次数据更新时,若版本号与数据库中的版本号匹配,更新成功并递增版本号;若不匹配,则表示数据已被其他用户修改,更新操作将失败。这通常通过`...
在Hibernate中,乐观锁通常通过版本字段(version)或者时间戳(timestamp)实现。当多个线程尝试同时更新同一数据时,只有版本号或时间戳匹配的更新才能成功,其他不匹配的更新会被回滚。这种方式减少了锁的使用,...
在Hibernate中,可以使用`@Version`注解来实现乐观锁,该注解会在实体类的一个属性上添加版本字段,每次更新时,Hibernate会比较当前版本号和数据库中的版本号,如果不同,则认为有并发冲突,更新失败。乐观锁的优点...
在这个例子中,`@Version`注解表示该字段用于实现乐观锁。当尝试更新记录时,Hibernate会检查版本号是否发生变化,如果发生变化则抛出异常。 **3. 乐观锁的优势与局限** - **优势**:乐观锁避免了长时间锁定数据的...
在Hibernate中,乐观锁通常通过版本号(Version)或时间戳(Timestamp)来实现。当多个事务尝试更新同一条记录时,如果某个事务的版本号与数据库中的不匹配,那么更新会被拒绝。这样可以避免锁竞争,提高并发性能,...
下面我们将深入探讨Java中乐观锁的原理、实现方式以及其在实际开发中的应用。 乐观锁的核心思想是:在读取数据时不会加锁,而是在更新数据时才会检查在此期间是否有其他线程修改了该数据。如果在检查时发现有其他...
4. **Hibernate乐观锁实现**:在Hibernate中,可以通过在实体类上添加`@Version`注解来启用乐观锁,该注解对应的字段会在数据库中自动生成并维护。在更新时,Hibernate会自动处理版本号的比较和更新。 5. **配置...
在Java中,可以使用`@Version`注解配合Hibernate框架来实现乐观锁。 悲观锁则采取相反的策略,它假设数据可能会被其他线程修改,所以在读取数据时就立即加锁,直到事务结束才释放锁。这样可以确保在读取数据到更新...
在Hibernate中,可以通过在实体类中添加一个`@Version`注解的字段来实现乐观锁。例如: ```java @Entity public class User { @Id private Long id; private String name; @Version private int version; // ...