未设置id时遇到StaleObjectStateException



我有一个DAO类,实现如下:

@Override
public void save(Employee emp) {        
Session curSession = entityManager.unwrap(Session.class);       
curSession.saveOrUpdate(emp);       
}

和一个实现如下的服务类:

@Override
@Transactional
public void save(Employee emp) {        
employeeDAO.save(emp);
}

当我执行这段代码时,它抛出了一个StaleObjectStateException:行被另一个事务更新或删除(或未保存值映射不正确)

但是如果我在调用DAO类之前设置id,它会工作得很好-

@Override
@Transactional
public void save(Employee emp) {
emp.setId(0);
employeeDAO.save(emp);
}

实体类-

@Entity
@Table(name="employee")
public class Employee {

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private int id;

@Column(name="first_name")
private String firstName;

@Column(name="last_name")
private String lastName;

@Column(name="email")
private String email;

public Employee() {     
}
public Employee(int id, String firstName, String lastName, String email) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
//getters and setters for the fields are present

谁能帮我理解到底发生了什么?

因为我不知道你的会话和DB的状态,当你得到陈旧的对象异常,我不能确定。然而,根据我的猜测,这里有一些可能的解决方案:

关于saveOrUpdate()的特征,请参考这个问题:Hibernate saveOrUpdate行为

  • 如果这个对象在这个会话中已经是持久的,什么都不做
  • 如果与会话关联的另一个对象具有相同的标识符,抛出异常
  • 如果对象没有标识符属性,保存()它
  • 如果对象的标识符具有分配给新实例化对象的值,则保存()它
  • 如果对象的版本由"version"或"时间戳",并且版本属性值与分配给新创建的属性的值相同实例化对象,保存()它,否则更新()对象

确保您没有在任何地方对同一对象调用两次saveOrUpdate(),因为这会导致陈旧的对象异常。

其次,参考这个问题:当我在空表上执行Hibernate saveOrUpdate时失败

这是设计的

Hibernate只根据id决定是否应该执行更新或者插入。如果它能考虑到已经存在的数据库,它必须执行一个额外的查询,但它没有这样做。

id通常由Hibernate管理,除非您将其映射为发电机="assigned"(不知道使用注释会是什么样子)。所以你不应该只是给它赋值。

在本例中,Id甚至由数据库给出。所以如果你应用程序将同时生成id,它将导致重复的id。(并且大多数数据库不允许插入值到自动列,因此在技术上不可能存储您的id)。

如果你想生成你自己的id,使用generator="assigned"和使用合并存储它。这将做您所期望的:它搜索记录在数据库中,当它存在时它会更新它,当它不存在时将插入。

因为Hibernate不会执行Select查询来执行更新或插入,所以请确保您没有手动在数据库中为应该由Hibernate管理的表创建记录。创建对象的实际实例,并将测试对象保存到DB中。

相关内容

最新更新