1

我正在尝试更新不同事务中的同一行以了解 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();

    }

我已将代码附加到我正在尝试做的事情之上。请让我知道..我错过了什么吗?

或者乐观锁定与我正在尝试做的事情不同。

在上面的代码中,我启动了两个线程“Earlier”和“Later”,它们都从 sessionFactory 获取会话对象并从数据库中加载相同的记录并同时更新它。

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)]
4

1 回答 1

2

这里发生的情况是脏检查在您不期望的情况下帮助您。airlineCode我敢打赌is的原始值asdasdbaadmain与您在“稍后”线程中设置的值相同。

Hibernate 有一个称为脏检查的过程,它检查每个字段以查看它是否已从最初加载的状态修改。在这种情况下,你没有改变任何东西。没有更改的字段意味着没有更新,没有执行 SQL,没有版本冲突,因此没有例外。

如果你调用你会得到异常session.evict()的事实是因为如果你已经从那里驱逐了实体,Session那么就没有什么可以进行脏检查了,所以 Hibernate 被迫写入数据库。

于 2013-03-29T04:52:23.347 回答