如何将 http 会话传递给 DeferredResult?

How can I pass http session to DeferredResult?

我有 Spring 个具有异步端点的 MVC 应用程序:

@GetMapping
public DeferredResult<Collection<B>> get() {
    DeferredResult<Collection<B>> result = new DeferredResult<>();
    Executors.newSingleThreadExecutor().submit(() -> result.setResult(service.getB()));
    return result;
}

我正在尝试使用 jackson-datatype-hibernate:

序列化惰性对象
@Entity
@Table
public class B {

    @Id
    @GeneratedValue
    private UUID id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "a_id")
    private A a;

    public A getA() {
        return a;
    }
}

但我得到:

Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.example.demo.B["a"])

我认为这里提到的会话是 Hibernate 会话而不是 HTTP 会话。

您的 POJO (B) 包含一个映射到 FetchType.LAZY 的属性 (A a),因此当读取该属性时,Hibernate 会话必须打开并可用,以便满足惰性抓取。

我怀疑您正在打开一个每个调用线程的会话,并且由于响应是在不同的线程上处理的,因此 Hibernate 会话在 B 被序列化的线程上不可用。您必须将一些状态(可能通过创建可执行文件 task/runner)传递给创建延迟结果的线程,您可以扩展它以在您委托时包括当前打开的 Hibernate 会话(并记住在你已经完成了那个线程)。或者,您也可以:

  • 在创建延迟结果的线程上打开一个新的 Hibernate 会话
  • 更改 FetchType,使其不再懒惰。