我有一个我正在努力解决的问题。我有一个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控制器的代码:
@RequestMapping(value = "/skill", method = RequestMethod.GET)
public ResponseEntity<List<Skill>> listAllSkills() {
Iterable<Skill> skills = skillService.getAllSkills();
return new ResponseEntity<>(Lists.newArrayList(skills), HttpStatus.OK);
}
每当我尝试从该控制器返回实体时,它都会抛出
JsonMappingException: failed to lazily initialize a collection of
role: com.juriy.arcadia.domain.Skill.children, could not initialize
proxy - no Session
据我了解,发生的事情是杰克逊在交易范围之外尝试实体的懒惰部分,这就是找不到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);
}
问题:在延迟加载和事务处理的情况下,组织反序列化的假设方法是什么。有没有办法将反序列化放在事务边界内?
相关问题:我听说制作控制器层@Transactional
不是一个好习惯。在这种情况下,设计交易的最佳方式是什么?
更新:在我的情况下添加EAGER
实体加载不是一个选项(有一个大的实体树,EAGER
加载将加载整个树,这将完全杀死表演。)
答案 0 :(得分:1)
杰克逊在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);
}
这假设您已正确设置了事务管理器。
答案 1 :(得分:0)
如果您要返回所有技能列表,则必须使用FetchType.EAGER。延迟加载不会在不直接访问数据的情况下加载数据。这就是你犯这个错误的原因。