项目中客户需要一个发布/编辑的功能,数据要存档。
我的方案设计是新建两张表,一张主表用于查询,一张临时表用于增删改。
增删改操作的表命名为XXX_temp,后台管理操作。后台操作完成后需要把临时表数据同步到主表中。
初始方案:根据条件查询临时表所有数据,java程序中判断主表中是否有数据,有数据进行更新,无数据插入。后来嫌判断麻烦,还需要写更新语句,索性重置主表数据,重新插入。
表结构:
/**
* 同步数据 BO.java
* @param request
* @return
* @throws ServiceException
*/
@Override
@Transactional(rollbackFor = Exception.class)
public CommonResponse syncPromotion(CommonRequest request) throws ServiceException {
UserPromotionListReqDto reqDto = new UserPromotionListReqDto();
CommonResponse response = new CommonResponse(request);
reqDto.setConsumerSign(false);
// 查询所有列表
UserPromotionListResDto resTempDto = promotionService.getUserPromotionList(reqDto);
// 初始化主表数据
promotionService.initPromotion();
// 插入
promotionService.insertPromotionBatch()
return response;
}
这样逻辑比较清晰,但是重复的查询、更新和插入,若数据量比较大、请求多必会引起阻塞。而且逻辑处理写在bo层,增删查改需要到dto层操作,初始化、查询、插入都需要建立dto,显得很麻烦。
解决方案:
Oracle中有 merge into 语句,能够合并两张表数据,
示例(原文链接:https://blog.csdn.net/qq_44772660/article/details/112285088):
MERGE A表 AS a
USING ( SELECT x.id, x.field_2, x.field_3,x.field_4 FROM B表 x )//查询有用的字段
AS b
ON a.id= b.id //匹配条件
WHEN MATCHED THEN //当匹配时执行update
UPDATE
SET a.field_2 = b.field_2
WHEN NOT MATCHED THEN //当不匹配时执行insert
INSERT (id,field_2,field_3,field_4) VALUES (b.id,b.field_2,b.field_3,b.field_4);
当A表中有数据时执行update,无数据执行insert
mysql 中无merge into 语法,可以改为 ON DUPLICATE KEY 实现
INSERT INTO promotion_info ( promotion_id) SELECT
promotion_id,
FROM promotion_info_temp
ON DUPLICATE KEY UPDATE promotion_id = VALUES ( promotion_id )
同步多个字段,以及有条件同步
INSERT INTO promotion_info ( promotion_id, image, NAME, position, certificate, qr_code, sort, delete_flag, release_flag )
SELECT promotion_id,image,NAME,position,certificate,qr_code,sort,delete_flag,release_flag
FROM promotion_info_temp
WHERE release_flag = 'N'
AND delete_flag = 'N'
ON DUPLICATE KEY
UPDATE promotion_id = VALUES( promotion_id ),
image = VALUES( image ),NAME = VALUES( NAME ),
position = VALUES( position ),certificate = VALUES( certificate ),
qr_code = VALUES( qr_code ),
sort = VALUES( sort ),
delete_flag = VALUES( delete_flag ),
release_flag = VALUES(release_flag)
注意:
若不想主表中数据重复,操作的字段中需要某字段有唯一索引,不然执行完后会出现同样的数据。且要避免多个唯一索引,例如如果
where a=1 OR b=2
匹配多个行,只有一个行被更新
简化java处理逻辑,避免重复查询,满足大多数需求。
①性能带来开销,尤其是系统比较大的时候。
②在高并发的情况下会出现错误,可能需要利用事务保证安全。
插入行为1 ,更新行为2,未更新为0
【ON DUPLICATE KEY UPDATE 用法与说明】https://blog.csdn.net/qq_43279637/article/details/92797641
【java 对两张表进行数据同步】https://blog.csdn.net/qq_44772660/article/details/112285088
【mysql手册】https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
仅供参考,欢迎讨论。若有错误,恳请指正