在单个事务中更新表的同一行时获取“org.hibernate.StaleObjectStateException”

时间:2012-08-26 21:05:16

标签: java hibernate

我有一个名为Employee的表,它有一个复杂的主键,即其列中的3个

的组合
firstName : String
SecondName : String
bossId : foreingKey of other table named Boss ( auto generated database sequence)

这是我的代码:

@Entity
@Table(name = "Employee")
@org.hibernate.annotations.Entity(optimisticLock = OptimisticLockType.ALL, dynamicUpdate = true)
public class Employee {

private EmployeePk employeePk;  

private int age;
private String status;


@EmbeddedId
public EmployeePk getEmployeePk() {
    return employeePk;
}
public void setEmployeePk(EmployeePk employeePk) {
    this.employeePk = employeePk;
}


@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null ||
            !(o instanceof Employee)) {

        return false;
    }

    Employee other
    = (Employee)o;

    // if the id is missing, return false
    if (getEmployeePk() == null) return false;


    if( getEmployeePk().equals(other.getEmployeePk())) {            
        return true;
    } else {
        return false;
    }

}

@Override
public int hashCode() {
    if (getEmployeePk() != null) {
        return getEmployeePk().hashCode();
    } else {
        return super.hashCode();
    }
}

}

@Embeddable
public class EmployeePk implements Serializable{

private static final long serialVersionUID = -7827123517392541880L;
private String firstName;
private String secondName;
private Boss boss;

@ManyToOne
@JoinColumn(name = "boss_id",insertable= false, updatable= false)
public Boss getBoss() {
    return boss;
}
public void setBoss(
        Boss boss) {
    this.boss = boss;
}

/* setters and getters of all with @column annotation */

@Override  
public boolean equals(Object obj) {  
    if (this == obj) {  
        return true;  
    }  
    if (!(obj instanceof EmployeePk)) {  
        return false;  
    }  

    EmployeePk other = (EmployeePk) obj;  

    if( getfirstname() != null && 
            getFirstName().equals(other.getFirstName()) &&
            getSecondName() !=null && 
            getSecondName().equals(other.getSecondName()) &&
            getBoss() != null &&
            getBoss().getId() == other.getBoss().getId())
        return true;

    return false;  
}  

@Override
public int hashCode() {
    if (getFirstName() != null &&
            getSecondName() != null && 
            getBoss() != null) {
        return getFirstName().hashCode() + 
                getSecondName().hashCode();
    } else {
        return super.hashCode();
    }
}

}

现在,一切运行正常,我可以在Employee表中创建/更新/删除数据库行。

但是当我尝试在一个单独的事务中更新相同的行时,我得到了这个例外:

org.hibernate.event.def.AbstractFlushingEventLis
tener: Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect):
    at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1792)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2435)
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2335)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2635)
    at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:64)
    at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:996)
    at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1141)
    at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
    at org.hibernate.impl.AbstractQueryImpl.uniqueResult(AbstractQueryImpl.java:835)

我与另一个名为Contractor的表有类似的问题但是能够通过覆盖它的equals和hashCode方法来解决这个问题。

问题是在那个表中只有一个名为“id”的主键是一个数据库自动生成的序列,因此 那里没有EmbeddedId的概念。

我不确定我在哪里出错了。我花了几天时间来解决这个问题并遵循了几个链接,例如:http://onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=1

1 个答案:

答案 0 :(得分:0)

有几点想法:

1)使用optimisticLock = OptimisticLockType.ALL让我怀疑。我自己从未使用过这个,但我怀疑它可能与你的错误有关。

2)我不认为equals方法处理任何属性为null的情况。即使两个实例都相同,它也总是返回false。

3)当你使用专用id(和版本,如果需要)列而不是自然键时,Hibernate真的更喜欢。根据我的经验,对复合/自然键的支持似乎很麻烦和错误。