当前位置: 首页 > 知识库问答 >
问题:

Hibernate乐观锁定:没有任何异常

司寇经亘
2023-03-14

我试图在不同的事务中更新同一行,以理解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)]

共有1个答案

陈实
2023-03-14

这里发生的事情是一个肮脏的检查在你意想不到的时候帮了你一把。我打赌< 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)。