java - Spring REST Controller ,在事务内部反序列化

标签 java spring rest jpa transactions

我有一个正在努力解决的问题。我有一个 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/

相关文章:

java - 404/503 错误的 Json 响应

java - 使用 Glide 从动态 URL 加载图像

java - 如何声明一个具有以 String 和 Map 作为参数的构造函数的 bean?

java - Spring MVC 在 Controller 类之外使用 Autowiring 对象

java - 使用 Spring Security 检查额外参数

java - 允许斜杠的 JAX-RS @Path 与其他资源发生冲突

RESTful Web 服务 - 返回操作结果的最佳方式?

java - 如何将 3D 矩阵逆时针旋转 90 度?

java - 使用具有透明像素的图像的 mouseListener 和 JLabels

java - 如何加载 util 类的属性