我有一个正在努力解决的问题。我有一个 JPA 实体,其中包含延迟加载的一组 @OneToMany
实体(代码如下)。
@Entity
@Table(name = "SKILL")
public class Skill {
@Id
@Column(name = "SKILL_ID")
@GeneratedValue(generator = "increment")
@GenericGenerator(name = "increment", strategy = "increment")
private Long id;
@Column(name = "NAME")
private String name;
@ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.MERGE})
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
@JsonIdentityReference(alwaysAsId=true)
private Skill parent;
@OneToMany(mappedBy="parent", cascade={CascadeType.ALL})
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
@JsonIdentityReference(alwaysAsId=true)
private Set<Skill> children;
public Skill() {
}
// getters-setters ommitted
}
这是来自 Spring REST Controller 的代码:
@RequestMapping(value = "/skill", method = RequestMethod.GET)
public ResponseEntity<List<Skill>> listAllSkills() {
Iterable<Skill> skills = skillService.getAllSkills();
return new ResponseEntity<>(Lists.newArrayList(skills), HttpStatus.OK);
}
每当我尝试从该 Controller 返回实体时,它都会抛出
JsonMappingException: failed to lazily initialize a collection of
role: com.juriy.arcadia.domain.Skill.children, could not initialize
proxy - no Session
据我了解,发生的情况是 Jackson 正在尝试在事务范围之外延迟加载实体的部分,这就是找不到 Session 的原因。如果我添加一个肮脏的黑客并调用应该在事务中手动延迟加载的部分,它就会起作用:
@RequestMapping(value = "/skill", method = RequestMethod.GET)
public ResponseEntity<List<Skill>> listAllSkills() {
Iterable<Skill> skills = skillService.getAllSkills();
// Hack here: load required items inside of session bounds
for (Skill s : skills) {
System.out.println("Fetched skills: "+ s.getChildren().size());
System.out.println("Fetched parent: "+ s.getParent());
}
return new ResponseEntity<>(Lists.newArrayList(skills), HttpStatus.OK);
}
问题:在延迟加载和事务的情况下组织反序列化的假定方法是什么。有没有办法将反序列化放在事务范围内?
相关问题:我听说将 Controller 层设为@Transactional
并不是一个好的做法。在这种情况下设计事务的最佳方法是什么?
更新: 在我的情况下,添加实体的 EAGER
加载不是一个选项(有一个很大的实体树,EAGER
加载将加载整棵树,这将完全破坏性能)。
最佳答案
Jackson 正在 JPA 事务之外调用父级上的 getter,因此延迟加载的实体不再可用。
更改为 Fetch.EAGER 或添加汇编器层(即将实体转换为 POJO 的层)。
或者添加@Transaction注解
@Transaction
@RequestMapping(value = "/skill", method = RequestMethod.GET)
public ResponseEntity<List<Skill>> listAllSkills() {
Iterable<Skill> skills = skillService.getAllSkills();
return new ResponseEntity<>(Lists.newArrayList(skills), HttpStatus.OK);
}
这假设您已正确设置事务管理器。
关于java - Spring REST Controller ,在事务内部反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40132758/