业务需求,有联表
实体A
@Entity
class A
{
@Id
private Long id;
@OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@JoinColumn(name = "aId")
@Fetch(FetchMode.SUBSELECT)
private Set<B> bs;
// GET SET toString
}
@Entity
class B
{
@Id
private Long id;
@Column
private String data;
// GET SET toString
}
然后因为业务比较复杂,所以采用的方式是先
save(A) // A.bs=null
save(B)
完成后,findById(A.id)发现A.bs仍为null,于是打开spring的debug日志,发现跟EntityManager有关
猜测:
1,Spring的EntityManager负责DO和事务
2,在findById时,EntityManager发现此实体已经在EM中维护,所以不再查找数据库(所以Hibernate只打印了一条查找A表的语句,而没有打印查找B表的语句,正常情况下,因为设置了
@Fetch(FetchMode.SUBSELECT)
,所以应该在查找A 的时候,也在B中查找,找不到的话,则返回空列表而不是空指针;而实际上,因为EM中维护了A,发现A中的bs为null,则不再查找B表了)
3,另外有测试,如果直接用controller调用findById,则能正常联表查找
4,如果用类似findAll之类的函数查找多条,则也会打印两条Hibernate,但是刚save的那一个仍然包含null的bs
5,讲Spring的debug打开后,发现貌似是一个线程维护一个EM,那么在3中,其实是新开了一个线程,使用了新的EM,所以能正常查找了
解决方法:
cascade=CascadeType.ALL
不用单独save B,直接将B的DO设置到A的bs中,然后jpa自动给同步