当我尝试从REST控制器中删除以下Customer对象时, “删除分离的实例” 例外。
LOG:
org.springframework.dao.InvalidDataAccessApiUsageException: Removing a detached instance com.test.model.Customer#1750; nested exception is java.lang.IllegalArgumentException: Removing a detached instance com.test.model.Customer#1750
域
@Entity
public class Customer{
@Id
private Long id;
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name="COUNTRY_ID", nullable=false)
private Country country;
// other stuff with getters/setters
}
REST控制器:
@Controller
@RequestMapping("/shop/services/customers")
public class CustomerRESTController {
/**
* Deletes a customer
*/
@RequestMapping( value="/{id}", method=RequestMethod.DELETE)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteCustomer(@PathVariable Long id, HttpServletRequest request, HttpServletResponse response) throws Exception {
Customer customer = customerService.getById(id);
if(customer != null){
customerService.delete(customer);
}else{
response.sendError(503, "No Customer found for ID : " + id);
}
}
// other stuff
}
我从Data Base获取Customer对象,但仍然在休眠抱怨。 有什么建议??
答案 0 :(得分:3)
实体在当前会话(或更好的事务)中分离。由于您在Spring中,因此使用Java Transaction Service (JTS)进行事务处理是很常见的。使用这样的Hibernate会在提交后自动清除持久化上下文(就像用作JPA解决方案时那样)。
通常,Hibernate不会清除会话的持久性上下文,因此您的实体通常在提交后不会分离。 (这在分布式环境中是不安全的,但如果仅使用Hibernate访问数据库并使用像Ehcache这样的分布式缓存,则会保存。)
解决方案:session.merge(object)
将您的实体重新附加到当前会话对象的持久性上下文中。
它实际上不是合并而是重新连接,如果Hibernate不确定实体的当前状态是否反映了正确的数据库缓存,它将重新加载实体。 (并且在版本属性(@Version)的呈现情况下添加特殊行为。)
顺便提一下Hibernate的文档说明:
将给定对象的状态复制到具有相同标识符的持久对象上。如果当前没有与会话关联的持久性实例,则将加载该实例。
<强>更新强>
看到你的代码后,这看起来像是一个交易问题。请检查您的customerService.getById(id)和customerService.delete(客户)服务调用是否导致事务提交。您需要将两者放在同一个交易中。
您还可以做的一件事也可以解决您的问题:
public void deleteCustomer(@PathVariable Long id, HttpServletRequest request, HttpServletResponse response) throws Exception {
boolean wasDeleted = customerService.delete(id);
if(!wasDeleted)
response.sendError(503, "No Customer found for ID : " + id);
}
}
这样您就不需要两次服务呼叫。实际上,在高级服务调用中使用hibernate实体是不典型的(但对于不同的体系结构可能会有所不同。我没有那么多地利用Spring。)