流水账记录最近增加的新数据到已有的数据里发生的问题。
M manyToOne A
A manyToOne B
B manyToOne C
B是AC的关联表,实际是为A增加C,AC是mTm关系。
为D增加C,E是关联表,DC 是mTm关系。
业务处理上,通过put API 配置M,在获取M entity后,增加新数据过程发生问题:
1. json Infinite recursion
如下链接非常好的解释了怎么处理该问题。在这次开发中非常tricky的是用jsonManagedReference/jsonBackReference没有解决这个问题,最后不得已用了jsonIgnore来解决。JsonIdentifyInfo是个很好的方案,但是出问题的entity里原来设计里把id给标记jsonIgnore了,无法使用JsonIdentifyInfo处理。
2.删除不必要的持有
在A<-->C里, C是独立的存在,最初的设计里C持有了set<B>,最后分析是没有必要的,而且在put M时对该set的维护成本巨大,最后删除。同理对待D和C。
3. JPA problem
3.1
在set M的过程中,写了一个方法设置A和C的关系,传参数M进去,在该方法里使用M.getA()获得A然后对A做多对多关系设定,结果在该方法里做JPA query时(query C )报错 “attempted to assign id from null one-to-one property M(D)”,非常tricky。最后修改该方法,在调用该方法前获取A,直接传A进去,错误消除
putM(MDto mDto){
...
MEntity mEntity = queryMEntity();
mapper.map(mDto,mEntity) // this is most of the jpa problem cause
setA(mDto,mEntity);
...
}
setA(mDto,mEntity){
aEntity = mEntity.getA();
cEntity = queryC(); // error here
.....
}
updated setA as below, then the error disapper
setA(mDto,aEntity){
....
cEntity = queryC();
.....
}
3.2 set完A后对D的新关系进行set,期间也有query C的操作,一样抛出各种奇怪的问题,比如
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [xx_id]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
用了各种办法解决,不停抛出要么这个constraintViolationExption,要么另一个数据constraintViolationExption。
最后分析发现,在set A和D 前,M被map了一部分DTO数据 (mapper.map(mDto,mEntity)),该操作时导致后面的set时多次做JPA query发生各种问题的根源。 最后解决方案是,在做该map前,把需要获取的C数据先拿到,然后在set给A和E。
4. 低级错误
期间还犯了一个低级错误,使用错误的japRepository进行数据的query,结果发现怎么都是返回的empty, 由于同时处理A,D,逻辑相似,用了A的关系repository去query D的关系数据。。。。期间以为是query写法问题,换了几个版本。。。。。浪费了几个小时时间,扣掉了好多头发。。