我试图在不同的事务中更新同一行,以理解Hibernate的乐观锁定。
但是我没有得到任何StaleObjectStateException或任何其他异常。
public void updateUsingTwoThreads() throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
public void run() {
Session session = null;
try {
session = HibernateUtil.getSessionFactory().openSession();
org.hibernate.Transaction transaction = session
.beginTransaction();
Airline airline = (Airline) session.get(Airline.class,
new Integer(1));
System.out.println("getVersion in "+airline.getVersion()+"in "+ Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
airline.setAirlineCode("asdasd234phle");
session.saveOrUpdate(airline);
System.out.println("getVersion in "+airline.getVersion()+"in "+ Thread.currentThread().getName());
transaction.commit();
}catch(Throwable t){
System.out.println(t);
}finally {
session.close();
}
}
},"earlier");
Thread t2 = new Thread(new Runnable() {
public void run() {
Session session = null;
try {
session = HibernateUtil.getSessionFactory().openSession();
//session.clear();
org.hibernate.Transaction transaction = session.beginTransaction();
Airline airline = (Airline) session.get(Airline.class,new Integer(1));
System.out.println("getVersion in "+airline.getVersion()+"in "+ Thread.currentThread().getName());
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("getVersion in "+airline.getVersion()+"in "+ Thread.currentThread().getName());
airline.setAirlineCode("asdasdbaadmain");
session.saveOrUpdate(airline);
transaction.commit();
}catch(Throwable t){
System.out.println(t);
} finally {
session.close();
}
}
},"later");
t1.start();
t2.start();
t1.join();
t2.join();
}
我已经在我正在尝试执行的操作上方附加了代码。请让我知道..我错过了什么吗?
或者乐观锁定与我正在尝试做的事情不同。
在上面的代码中,我启动了两个线程“早些时候”和“晚些时候”,它们都从会话工厂获取会话对象,并从数据库加载相同的记录并同时更新它。
1)但没有异常出现,而且只有一个线程能够更新该行。
航空公司等级如下:
package tryouts.one_to_many;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Version;
import org.hibernate.annotations.OptimisticLockType;
@Entity
@org.hibernate.annotations.Entity(dynamicUpdate=true, optimisticLock = OptimisticLockType.ALL)
public class Airline implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AIRLINE_ID")
private Integer airlineId;
@Column(name = "AIRLINE_NAME")
private String airlineName;
@Column(name = "AIRLINE_CODE")
private String airlineCode;
@Version
private long version;
@OneToMany
@JoinColumn(name="airlineId")
private Set<AirlineFlight> airlineFlights = new HashSet<AirlineFlight>();
public Integer getAirlineId() {
return airlineId;
}
public void setAirlineId(Integer airlineId) {
this.airlineId = airlineId;
}
public String getAirlineName() {
return airlineName;
}
public void setAirlineName(String airlineName) {
this.airlineName = airlineName;
}
public String getAirlineCode() {
return airlineCode;
}
public void setAirlineCode(String airlineCode) {
this.airlineCode = airlineCode;
}
public Set<AirlineFlight> getAirlineFlights() {
return airlineFlights;
}
public void setAirlineFlights(Set<AirlineFlight> airlineFlights) {
this.airlineFlights = airlineFlights;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
}
程序输出:
04:25:29.656 [earlier] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13645311296
04:25:29.656 [later] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13645311296
04:25:29.657 [earlier] DEBUG o.h.transaction.JDBCTransaction - begin
04:25:29.657 [later] DEBUG o.h.transaction.JDBCTransaction - begin
04:25:29.657 [earlier] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection
04:25:29.657 [later] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection
04:25:29.657 [earlier] DEBUG o.h.transaction.JDBCTransaction - current autocommit status: false
04:25:29.657 [later] DEBUG o.h.c.DriverManagerConnectionProvider - opening new JDBC connection
04:25:29.659 [earlier] DEBUG org.hibernate.loader.Loader - loading entity: [tryouts.one_to_many.Airline#1]
04:25:29.663 [earlier] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
04:25:29.663 [earlier] DEBUG org.hibernate.SQL - select airline0_.AIRLINE_ID as AIRLINE1_0_0_, airline0_.AIRLINE_CODE as AIRLINE2_0_0_, airline0_.AIRLINE_NAME as AIRLINE3_0_0_, airline0_.version as version0_0_ from Airline airline0_ where airline0_.AIRLINE_ID=?
Hibernate: select airline0_.AIRLINE_ID as AIRLINE1_0_0_, airline0_.AIRLINE_CODE as AIRLINE2_0_0_, airline0_.AIRLINE_NAME as AIRLINE3_0_0_, airline0_.version as version0_0_ from Airline airline0_ where airline0_.AIRLINE_ID=?
04:25:29.680 [later] DEBUG o.h.c.DriverManagerConnectionProvider - created connection to: jdbc:mysql://localhost:3306/test, Isolation Level: 4
04:25:29.681 [later] DEBUG o.h.transaction.JDBCTransaction - current autocommit status: false
04:25:29.681 [later] DEBUG org.hibernate.loader.Loader - loading entity: [tryouts.one_to_many.Airline#1]
04:25:29.681 [later] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 1)
04:25:29.681 [later] DEBUG org.hibernate.SQL - select airline0_.AIRLINE_ID as AIRLINE1_0_0_, airline0_.AIRLINE_CODE as AIRLINE2_0_0_, airline0_.AIRLINE_NAME as AIRLINE3_0_0_, airline0_.version as version0_0_ from Airline airline0_ where airline0_.AIRLINE_ID=?
Hibernate: select airline0_.AIRLINE_ID as AIRLINE1_0_0_, airline0_.AIRLINE_CODE as AIRLINE2_0_0_, airline0_.AIRLINE_NAME as AIRLINE3_0_0_, airline0_.version as version0_0_ from Airline airline0_ where airline0_.AIRLINE_ID=?
04:25:29.682 [later] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
04:25:29.682 [earlier] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
04:25:29.683 [later] DEBUG org.hibernate.loader.Loader - result row: EntityKey[tryouts.one_to_many.Airline#1]
04:25:29.683 [earlier] DEBUG org.hibernate.loader.Loader - result row: EntityKey[tryouts.one_to_many.Airline#1]
04:25:29.687 [later] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 2)
04:25:29.687 [earlier] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 2)
04:25:29.687 [later] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 2)
04:25:29.687 [earlier] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 2)
04:25:29.688 [later] DEBUG org.hibernate.engine.TwoPhaseLoad - resolving associations for [tryouts.one_to_many.Airline#1]
04:25:29.689 [earlier] DEBUG org.hibernate.engine.TwoPhaseLoad - resolving associations for [tryouts.one_to_many.Airline#1]
04:25:29.695 [earlier] DEBUG org.hibernate.engine.TwoPhaseLoad - done materializing entity [tryouts.one_to_many.Airline#1]
04:25:29.695 [later] DEBUG org.hibernate.engine.TwoPhaseLoad - done materializing entity [tryouts.one_to_many.Airline#1]
04:25:29.695 [earlier] DEBUG o.h.e.StatefulPersistenceContext - initializing non-lazy collections
04:25:29.695 [later] DEBUG o.h.e.StatefulPersistenceContext - initializing non-lazy collections
04:25:29.695 [earlier] DEBUG org.hibernate.loader.Loader - done entity load
04:25:29.695 [later] DEBUG org.hibernate.loader.Loader - done entity load
getVersion in 53in earlier
getVersion in 53in later
getVersion in 53in earlier
04:25:31.697 [earlier] DEBUG o.h.transaction.JDBCTransaction - commit
04:25:31.697 [earlier] DEBUG o.h.e.d.AbstractFlushingEventListener - processing flush-time cascades
04:25:31.699 [earlier] DEBUG o.h.e.d.AbstractFlushingEventListener - dirty checking collections
04:25:31.704 [earlier] DEBUG org.hibernate.engine.Collections - Collection found: [tryouts.one_to_many.Airline.airlineFlights#1], was: [tryouts.one_to_many.Airline.airlineFlights#1] (uninitialized)
04:25:31.704 [earlier] DEBUG o.h.e.d.AbstractFlushingEventListener - Flushed: 0 insertions, 1 updates, 0 deletions to 1 objects
04:25:31.704 [earlier] DEBUG o.h.e.d.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 1 collections
04:25:31.705 [earlier] DEBUG org.hibernate.pretty.Printer - listing entities:
04:25:31.705 [earlier] DEBUG org.hibernate.pretty.Printer - tryouts.one_to_many.Airline{airlineFlights=<uninitialized>, airlineCode=asdasd234phle, airlineName=Jet Airways, airlineId=1, version=53}
04:25:31.707 [earlier] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
04:25:31.707 [earlier] DEBUG org.hibernate.SQL - update Airline set AIRLINE_CODE=?, version=? where AIRLINE_ID=? and version=?
Hibernate: update Airline set AIRLINE_CODE=?, version=? where AIRLINE_ID=? and version=?
04:25:31.708 [earlier] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
04:25:31.711 [earlier] DEBUG o.h.transaction.JDBCTransaction - committed JDBC Connection
04:25:31.711 [earlier] DEBUG org.hibernate.jdbc.ConnectionManager - aggressively releasing JDBC connection
04:25:31.711 [earlier] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
getVersion in 53in later
04:27:09.695 [later] DEBUG o.h.transaction.JDBCTransaction - commit
04:27:09.696 [later] DEBUG o.h.e.d.AbstractFlushingEventListener - processing flush-time cascades
04:27:09.696 [later] DEBUG o.h.e.d.AbstractFlushingEventListener - dirty checking collections
04:27:09.696 [later] DEBUG org.hibernate.engine.Collections - Collection found: [tryouts.one_to_many.Airline.airlineFlights#1], was: [tryouts.one_to_many.Airline.airlineFlights#1] (uninitialized)
04:27:09.696 [later] DEBUG o.h.e.d.AbstractFlushingEventListener - Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects
04:27:09.696 [later] DEBUG o.h.e.d.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 1 collections
04:27:09.696 [later] DEBUG org.hibernate.pretty.Printer - listing entities:
04:27:09.696 [later] DEBUG org.hibernate.pretty.Printer - tryouts.one_to_many.Airline{airlineFlights=<uninitialized>, airlineCode=asdasdbaadmain, airlineName=Jet Airways, airlineId=1, version=53}
04:27:09.697 [later] DEBUG o.h.transaction.JDBCTransaction - committed JDBC Connection
04:27:09.697 [later] DEBUG org.hibernate.jdbc.ConnectionManager - aggressively releasing JDBC connection
04:27:09.697 [later] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
这里发生的事情是一个肮脏的检查在你意想不到的时候帮了你一把。我打赌< code>airlineCode的原始值是< code > asdasdbadmain ,与您在' later '线程中设置的值相同。
Hibernate有一个称为脏检查的过程,它检查每个字段,看看它是否从最初加载的状态修改过。在这种情况下,你没有改变任何东西。没有未更改的字段意味着没有更新,没有执行SQL,没有版本冲突,因此没有异常。
如果您调用< code>session.evict()就会得到异常,这是因为如果您已经从< code>Session中驱逐了实体,那么就没有什么要进行脏检查的了,因此Hibernate被迫写入数据库。
我有一个这样的方法: 我希望通过使用REQUIRES_NEW事务传播和所示的递归,StaleObjectStateException最终会被清除,但事实并非如此。 如何从此异常恢复?
我有一个带有和的微服务。我使用注释对中的表执行操作。我遇到的问题是保存操作花费了太多的时间,所以我希望读取操作不被它阻塞。注意,保存是通过持久化实体来执行的。 当前,在所有并发保存操作完成之前,所有读取操作都不会返回结果,这意味着表被锁定。相反,我希望实现乐观锁定。我怎样才能做到呢?
我使用SpringDataJPA和Hibernate作为PostgreSQL上的持久性提供者。我试图提供悲观锁定: 我尝试从两个线程中调用< code>findOneAndLock。我认为,如果< code >线程A锁定了对象,那么< code >线程B应该等到锁被释放。而是< code >线程B抛出< code > org . spring framework . ORM . objectopt
我们有一个系统,我们偶尔会得到一个乐观的锁定异常。我们在代码中已经解决了这个问题,但现在我正在查看JPA 2,并看到它有一个用于处理这个问题的注释(@版本) 我们的问题是,一个表上有多个事务,如果表锁已满,则即使未对相同的记录进行更改,也会导致乐观锁定异常。 我们在JBoss 4.2服务器上使用hibernate,数据库可以是MySQL或SQL服务器。 如果改为使用@Version,这会在两个数据
在多用户环境中,在同一时间可能会有多个用户更新相同的记录,会产生冲突,解决方案有两种:乐观锁、悲观锁。 悲观锁在这里不讲,自行Google。 乐观锁假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性,不完整则更新失败。 乐观锁实现方式 使用整数表示数据版本号.更新时检查版本号是否一致,如果相等,则更新成功,且版本号+1.如果不等,则数据已经被修改过,更新失败。 使用时间戳来实现。 本质上也
在同一个表中的一个并发插入操作中,我得到了ConstraintViolationException。 Hibernate乐观锁在这方面能帮我吗?据我所知,乐观锁定适用于数据库中同一记录的更新/删除操作。 它也适用于插入查询吗? 我在目标表(实体)中创建了一个版本列。但仍然得到相同的异常(没有乐观的LockException或StaleObjectStateException)。