项目使用spring data jpa ,
在配置了 多对1 和 1对 多的 表 对象关联关系之后,
同事 发现查询出来的 多的一方 ,有两个数据,而且他们的 数据id 都是一样的。
开始 他们以为是 阿里的json 序列化的时候,因为 有重复引用,循环引用问题,导致了 这个 BUG。
但是 他 设置了 fastjson 禁止 重复引用,循环引用,都不能解决。
刚好我 注意到了,就去 了解一下这个BUG。 开始也以为是 阿里fastjson 的BUG,
但是在我 debug 查看数据的时候,发现 明细表 就是有两条一样的数据的。
那就是 他们配置 关系的时候配置错了。
关联对象代码:
一方:
@OneToMany(fetch = FetchType.EAGER, mappedBy = "trade")
private List<TcOrder> orderList = new ArrayList<>();
多方:
/**
* 父订单ID
*/
@Column(name = "trade_id", nullable = true, length = 19)
private Long tradeId;
@ManyToOne()
@JoinColumn(name = "trade_id", unique = true, insertable = false, updatable = false)
@JSONField(serialize = false)
private TcTrade trade;
这配置 查询的时候的SQL
select
tctrade0_.id as id1_158_0_,
tctrade0_.account_status as account_2_158_0_,
tctrade0_.addres_id as addres_i3_158_0_,
tctrade0_.biz_type as biz_type4_158_0_,
tctrade0_.buyer_id as buyer_id5_158_0_,
tctrade0_.buyer_name as buyer_na6_158_0_,
tctrade0_.buyer_org_id as buyer_or7_158_0_,
tctrade0_.buyer_type as buyer_ty8_158_0_,
tctrade0_.cancel_reason as cancel_r9_158_0_,
tctrade0_.cancel_time as cancel_10_158_0_,
tctrade0_.cancel_type as cancel_11_158_0_,
tctrade0_.channel as channel12_158_0_,
tctrade0_.create_time as create_13_158_0_,
tctrade0_.customer_id as custome14_158_0_,
tctrade0_.customer_name as custome15_158_0_,
tctrade0_.customer_nick_name as custome16_158_0_,
tctrade0_.dealer_id as dealer_17_158_0_,
tctrade0_.dealer_name as dealer_18_158_0_,
tctrade0_.delivery_amount as deliver19_158_0_,
tctrade0_.delivery_status as deliver20_158_0_,
tctrade0_.delivery_way as deliver21_158_0_,
tctrade0_.discount_amount as discoun22_158_0_,
tctrade0_.fans_id as fans_id23_158_0_,
tctrade0_.fee_item_amount as fee_ite24_158_0_,
tctrade0_.follower_id as followe25_158_0_,
tctrade0_.follower_org_id as followe26_158_0_,
tctrade0_.goods_amount as goods_a27_158_0_,
tctrade0_.have_invoice as have_in28_158_0_,
tctrade0_.hedge_type as hedge_t29_158_0_,
tctrade0_.income_amount as income_30_158_0_,
tctrade0_.invoice_id as invoice31_158_0_,
tctrade0_.invoice_no as invoice32_158_0_,
tctrade0_.min_send_amount as min_sen33_158_0_,
tctrade0_.modify_time as modify_34_158_0_,
tctrade0_.order_type as order_t35_158_0_,
tctrade0_.org_id as org_id36_158_0_,
tctrade0_.pay_amount as pay_amo37_158_0_,
tctrade0_.pay_status as pay_sta38_158_0_,
tctrade0_.pay_time as pay_tim39_158_0_,
tctrade0_.payment_id as payment40_158_0_,
tctrade0_.payment_no as payment41_158_0_,
tctrade0_.promoter_id as promote42_158_0_,
tctrade0_.promoter_name as promote43_158_0_,
tctrade0_.promoter_org_id as promote44_158_0_,
tctrade0_.promoter_type as promote45_158_0_,
tctrade0_.refunded_amount as refunde46_158_0_,
tctrade0_.remark as remark47_158_0_,
tctrade0_.remind_delivery as remind_48_158_0_,
tctrade0_.removed as removed49_158_0_,
tctrade0_.require_deliver_date as require50_158_0_,
tctrade0_.seller_id as seller_51_158_0_,
tctrade0_.seller_name as seller_52_158_0_,
tctrade0_.seller_org_id as seller_53_158_0_,
tctrade0_.seller_type as seller_54_158_0_,
tctrade0_.source_id as source_55_158_0_,
tctrade0_.source_no as source_56_158_0_,
tctrade0_.staff_id as staff_i57_158_0_,
tctrade0_.staff_name as staff_n58_158_0_,
tctrade0_.store_id as store_i59_158_0_,
tctrade0_.store_name as store_n60_158_0_,
tctrade0_.total_amount as total_a61_158_0_,
tctrade0_.trade_img as trade_i62_158_0_,
tctrade0_.trade_no as trade_n63_158_0_,
tctrade0_.trade_status as trade_s64_158_0_,
tctrade0_.uuid as uuid65_158_0_,
orderlist1_.trade_id as trade_i29_146_1_,
orderlist1_.id as id1_146_1_,
orderlist1_.id as id1_146_2_,
orderlist1_.brand_id as brand_id2_146_2_,
orderlist1_.brand_name as brand_na3_146_2_,
orderlist1_.create_time as create_t4_146_2_,
orderlist1_.customer_id as customer5_146_2_,
orderlist1_.customer_name as customer6_146_2_,
orderlist1_.customer_nick_name as customer7_146_2_,
orderlist1_.dealer_id as dealer_i8_146_2_,
orderlist1_.dealer_name as dealer_n9_146_2_,
orderlist1_.delivery_amount as deliver10_146_2_,
orderlist1_.discount_amount as discoun11_146_2_,
orderlist1_.express_code as express12_146_2_,
orderlist1_.express_name as express13_146_2_,
orderlist1_.express_no as express14_146_2_,
orderlist1_.fans_id as fans_id15_146_2_,
orderlist1_.goods_amount as goods_a16_146_2_,
orderlist1_.income_amount as income_17_146_2_,
orderlist1_.modify_time as modify_18_146_2_,
orderlist1_.order_img as order_i19_146_2_,
orderlist1_.order_no as order_n20_146_2_,
orderlist1_.order_state as order_s21_146_2_,
orderlist1_.org_id as org_id22_146_2_,
orderlist1_.removed as removed23_146_2_,
orderlist1_.staff_id as staff_i24_146_2_,
orderlist1_.staff_name as staff_n25_146_2_,
orderlist1_.store_id as store_i26_146_2_,
orderlist1_.store_name as store_n27_146_2_,
orderlist1_.total_amount as total_a28_146_2_,
orderlist1_.trade_id as trade_i29_146_2_,
itemlist2_.order_id as order_i24_147_3_,
itemlist2_.id as id1_147_3_,
itemlist2_.id as id1_147_4_,
itemlist2_.actual_price as actual_p2_147_4_,
itemlist2_.appraise_id as appraise3_147_4_,
itemlist2_.category_id as category4_147_4_,
itemlist2_.category_name as category5_147_4_,
itemlist2_.create_time as create_t6_147_4_,
itemlist2_.dealer_id as dealer_i7_147_4_,
itemlist2_.dealer_name as dealer_n8_147_4_,
itemlist2_.deliver_num as deliver_9_147_4_,
itemlist2_.deliver_status as deliver10_147_4_,
itemlist2_.deliver_time as deliver11_147_4_,
itemlist2_.discount_price as discoun12_147_4_,
itemlist2_.express_code as express13_147_4_,
itemlist2_.express_name as express14_147_4_,
itemlist2_.express_no as express15_147_4_,
itemlist2_.goods_id as goods_i16_147_4_,
itemlist2_.goods_no as goods_n17_147_4_,
itemlist2_.goods_title as goods_t18_147_4_,
itemlist2_.item_img as item_im19_147_4_,
itemlist2_.item_state as item_st20_147_4_,
itemlist2_.item_type as item_ty21_147_4_,
itemlist2_.modify_time as modify_22_147_4_,
itemlist2_.num as num23_147_4_,
itemlist2_.order_id as order_i24_147_4_,
itemlist2_.original_price as origina25_147_4_,
itemlist2_.remark as remark26_147_4_,
itemlist2_.removed as removed27_147_4_,
itemlist2_.return_num as return_28_147_4_,
itemlist2_.sale_price as sale_pr29_147_4_,
itemlist2_.sale_type as sale_ty30_147_4_,
itemlist2_.share_price as share_p31_147_4_,
itemlist2_.shipper_id as shipper32_147_4_,
itemlist2_.shipper_name as shipper33_147_4_,
itemlist2_.sku_id as sku_id34_147_4_,
itemlist2_.sku_no as sku_no35_147_4_,
itemlist2_.source_id as source_36_147_4_,
itemlist2_.source_item_id as source_37_147_4_,
itemlist2_.source_no as source_38_147_4_,
itemlist2_.source_type as source_39_147_4_,
itemlist2_.specification as specifi40_147_4_,
itemlist2_.store_id as store_i41_147_4_,
itemlist2_.store_name as store_n42_147_4_,
itemlist2_.trade_id as trade_i43_147_4_
from
tc_trade tctrade0_
left outer join
tc_order orderlist1_
on tctrade0_.id=orderlist1_.trade_id
left outer join
tc_order_item itemlist2_
on orderlist1_.id=itemlist2_.order_id
where
tctrade0_.id=175010
有 两个 left join 就是这里导致 出现 重复的明细数据
旧代码, 多方的配置方法与我的方法不一样。 配置了 @ManyToOne 正常来说,就不要配置 @JoinColumn 了。
这里配置了, 如果去掉 @JoinColumn 又会报错,因为 配置有 tradeId ,有重复了。这样的话,就可能需要改代码了。
会可能出BUG的。
解决办法
1. 但是也有其他方式 去改了,比如 查询 之后, 再查一遍 明细 order 数据, 重复赋值即可。
2. 改为 懒加载就可以解决了,不要使用 EAGER ,也比较影响性能
fetch = FetchType.LAZY