【发布时间】:2018-06-11 15:24:13
【问题描述】:
假设我的课程 A 和 B 具有从 A 到 B 的一对一关联。
@Entity
class A {
@Id Long id;
@OneToOne(fetch = LAZY) B b;
// getters, setters
}
@Entity
class B {
@Id Long id;
}
使用 Spring JPA,我有一个 A 的存储库,如下所示
@Repository
public interface ARepository extends JpaRepository<A, Long> {
A findById(Long id);
void delete(Long id);
}
最后是一个 REST 控制器
@RestController
@RequestMapping("/a")
class AController {
@Autowired ARepository repo;
@GetMapping("{id}")
public A getA(@PathVariable Long id) {
return repo.findById(id);
}
@Transactional
@DeleteMapping("{id}")
public A deleteA(@PathVariable Long id) {
A a = repo.findById(id);
repo.delete(id);
return a;
}
}
问题
假设我已将A 和id = 1 的实例保存到数据库中,当我向/a/1 发送GET 请求时,它会毫无问题地返回A 的JSON 表示。
但是当我尝试通过向/a/1 发送删除请求来删除实例时,我得到了com.fasterxml.jackson.databind.JsonMappingException,其根本原因如下
org.hibernate.LazyInitializationException: 延迟初始化集合失败,无法初始化代理 - 没有会话
问题
我的理解是,发生这个错误是因为Jackson在Hibernate会话的生命周期结束的方法deleteA()完成后试图通过调用a.getB()来序列化实例,这是正确的吗?
如果是这样,我不明白为什么方法getA()不会出现这个错误,我认为Hibernate会话应该在repo.findById(id);完成后立即结束,对吧?
【问题讨论】:
-
您的控制器是否使用弹簧启动?
-
I don't understand why this error doesn't occur in method getA(),(如果您使用的是 Spring Boot),您会发现同样的问题 here。对于您的第一个问题和 AFAIK,您的deleteA(Long)方法中不应包含LazyInitializationException,因为Session将用于获取类似于getA()方法的B数据。 -
@O.Badr,感谢您的回答。我使用 Spring Boot。我按照您建议的链接尝试将
open-in-view设置为false,然后方法getA()出现错误。但是当我将open-in-view设置为true 时,getA()不会出错,但deleteA()会出错。我尝试从deleteA()中删除repo.delete(id);并且它开始工作。所以我怀疑这可能与repo.delete(id);方法有关? -
我已经测试了你的代码,
deleteA()没有任何异常,你使用的是哪个版本的 Spring Boot?尽量不要在deleteA()方法中返回a对象(用 ResponseEnity 和HttpStatus代替,例如ResponseEntity.ok())?
标签: spring hibernate jpa jackson lazy-initialization