删除时删除分离的实例错误

时间:2013-09-29 12:54:00

标签: java spring hibernate rest

当我尝试从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对象,但仍然在休眠抱怨。 有什么建议??

1 个答案:

答案 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。)

相关问题