,Student.java
package com.fgh.hibernate;
import java.sql.Timestamp;
public class Student {
private String id;
private String name;
private int age;
private String cardId;
// private Timestamp lastDate;
private int version;
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = 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 getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
// public Timestamp getLastDate() {
// return lastDate;
// }
//
// public void setLastDate(Timestamp lastDate) {
// this.lastDate = lastDate;
// }
}
Student.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.fgh.hibernate.Student"
table="student_optimistic">
<id name="id" column="id" type="string">
<generator class="uuid"></generator>
</id>
<!-- 这个位置要放在property之前 timestamp和version本质上是一样的 -->
<!-- <timestamp name="timestamp" column="lastDate"></timestamp> -->
<version name="version" column="version" type="integer"></version>
<property name="name" column="name" type="string"></property>
<property name="cardId" column="cardId" type="string"></property>
<property name="age" column="age" type="integer"></property>
</class>
</hibernate-mapping>
测试类HibernateTest.java
package com.fgh.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class HibernateTest {
private static SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure()
.buildSessionFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 生成两个session 模拟双线程并发
Session session1 = sessionFactory.openSession();
Session session2 = sessionFactory.openSession();
//Transaction tx = null;
Transaction tx1 = null;
Transaction tx2 = null;
try {
/**保存操作
tx = session.beginTransaction();
Student student = new Student();
student.setAge(20);
student.setCardId("123");
student.setName("zhangsan");
session.save(student);
tx.commit();
*/
// 使用HQL查询 :name叫命名参数 調用setString方法为参数设值
// 然后调用uniqueResult方法返回唯一的对象
Student student1 = (Student) session1.createQuery(
"from Student s where s.name=:name").setString("name",
"zhangsan").uniqueResult();
Student student2 = (Student) session2.createQuery(
"from Student s where s.name=:name").setString("name",
"zhangsan").uniqueResult();
System.out.println(student1.getVersion());
System.out.println(student2.getVersion());
// 线程1 修改了name属性 然后提交事务 单独执行 线程1
// 打印出student2的version为0 因为线程2事务还没有提交
tx1 = session1.beginTransaction();
student1.setName("lisi");
tx1.commit();
System.out.println(student1.getVersion());
System.out.println(student2.getVersion());
// 线程2 同样修改了name属性 但是在此之前 已经对name属性做了修改
// 查询的时候name已更新为lisi 所以该处会抛异常StaleObjectStateException
//student1 version=1 student2 version=0
tx2 = session2.beginTransaction();
student2.setName("wangwu");
tx2.commit();
} catch (Exception e) {
e.printStackTrace();
if (null != tx1) {
tx1.rollback();
} else if (null != tx2) {
tx2.rollback();
}
} finally {
session1.close();
session2.close();
}
}
}
整体执行结果:
Hibernate: select student0_.id as id0_, student0_.version as version0_, student0_.name as name0_, student0_.cardId as cardId0_, student0_.age as age0_ from student_optimistic student0_ where student0_.name=?
Hibernate: select student0_.id as id0_, student0_.version as version0_, student0_.name as name0_, student0_.cardId as cardId0_, student0_.age as age0_ from student_optimistic student0_ where student0_.name=?
0
0
Hibernate: update student_optimistic set version=?, name=?, cardId=?, age=? where id=? and version=?
1
0
Hibernate: update student_optimistic set version=?, name=?, cardId=?, age=? where id=? and version=?
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.fgh.hibernate.Student#8a8ae4d934d2705b0134d2705cfb0001]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1765)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2407)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2307)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2607)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:92)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at com.fgh.hibernate.HibernateTest.main(HibernateTest.java:56)
Exception in thread "main" org.hibernate.TransactionException: Transaction not successfully started
at org.hibernate.transaction.JDBCTransaction.rollback(JDBCTransaction.java:149)
at com.fgh.hibernate.HibernateTest.main(HibernateTest.java:63)
分享到:
相关推荐
【Hibernate乐观锁与悲观锁详解】 在开发过程中,尤其是在并发环境下,确保数据的一致性和完整性至关重要。Hibernate,作为Java领域广泛使用的ORM框架,提供了一种处理并发数据访问冲突的手段,那就是锁机制。主要...
在Hibernate源码中,乐观锁的实现主要依赖于`AbstractEntityPersister`类的`checkOptimisticLocking()`方法,它会比较当前对象的版本信息与数据库中的版本信息,如果不同则抛出`StaleObjectStateException`异常。...
Hibernate乐观锁是数据库事务控制的一种策略,主要用于处理并发更新数据的情况。在乐观锁的机制下,假设并发用户很少会发生冲突,所以在读取数据时不会进行任何锁定,而在更新数据时才会检查在此期间是否有其他用户...
在Hibernate中,通常通过在实体类的映射文件中设置`optimistic-lock`属性来实现乐观锁,比如设置为`version`,这将利用数据库的版本字段来检测并发冲突。当尝试更新时,如果发现版本号已变,说明有其他事务进行了...
### Hibernate的乐观锁与悲观锁 #### 一、引言 在并发环境下,尤其是在金融、电商等业务场景中,确保数据的一致性和完整性至关重要。**Hibernate**作为一种流行的Java持久层框架,提供了多种机制来处理并发控制...
**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乐观锁的XML配置后,我们可以结合源码进一步分析其实现细节。在Hibernate中,乐观锁的处理主要在`org.hibernate.event.internal.DefaultMergeEventListener`和`org.hibernate.event.internal....
Hibernate推荐的乐观锁实现是通过在实体类中添加一个版本字段,每次数据更新时,若版本号与数据库中的版本号匹配,更新成功并递增版本号;若不匹配,则表示数据已被其他用户修改,更新操作将失败。这通常通过`...
在Hibernate中,乐观锁通常通过版本字段(version)或者时间戳(timestamp)实现。当多个线程尝试同时更新同一数据时,只有版本号或时间戳匹配的更新才能成功,其他不匹配的更新会被回滚。这种方式减少了锁的使用,...
常见的实现方式是在版本字段或时间戳字段上进行比较。在Hibernate中,可以使用`@Version`注解来实现乐观锁,该注解会在实体类的一个属性上添加版本字段,每次更新时,Hibernate会比较当前版本号和数据库中的版本号,...
乐观锁 求助编辑百科名片相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库 性能的大量开销,特别是对长事务而...
常见的乐观锁实现方式有两种:版本号机制和CAS(Compare and Swap)算法。 1. 版本号机制:在数据表中增加一个版本字段,每次读取数据时都记录当前版本号,当更新数据时,会比较当前版本号与数据库中的版本号是否...
### Java中的悲观锁与乐观锁实现详解 #### 一、悲观锁(Pessimistic Locking) 悲观锁是一种基于对数据安全性的保守态度而设计的锁机制。它假设数据在处理过程中很可能被外界修改,因此在整个数据处理过程中都会将...
在多线程环境下,为了保证数据的一致性和完整性,数据库管理系统提供了多种锁定机制,其中乐观锁和悲观锁是两种常见的实现方式。 1. **悲观锁**:悲观锁假设数据在操作过程中可能会被其他并发事务修改,因此在读取...
Hibernate 实现悲观锁和乐观锁代码介绍 Hibernate 是一个基于 Java 的持久层框架,它提供了多种锁机制来实现事务的隔离性和一致性。在本文中,我们将详细介绍 Hibernate 实现悲观锁和乐观锁的代码实现,并讨论 ...
在Hibernate框架中,乐观锁的实现方式之一是通过`version`字段,也就是我们这个练习的主题。`version`字段通常是一个整数或时间戳,记录了数据的版本信息。每次数据更新时,Hibernate会自动将`version`字段加一或者...
4. **Hibernate乐观锁实现**:在Hibernate中,可以通过在实体类上添加`@Version`注解来启用乐观锁,该注解对应的字段会在数据库中自动生成并维护。在更新时,Hibernate会自动处理版本号的比较和更新。 5. **配置...