@Transactional和Date时间引起推送数据失败
问题描述和需求背景
编码过程中难免有三方系统对接,推送数据,或者接收数据。这时会考虑到定时器,中间件…
需求背景: 就说A系统和B系统吧,我在A系统开发,生成的待办数据,要同步到B系统,开始是两个系统业务对接,考虑到以下几点:
1,生成待办数据 可能入库会失败想到了 spring的事务 @Transactional(rollbackFor = Exception.class)
2,推送待办数据到B系统 写一个定时任务读取数据,推送约束好的数据JSON 格式
代码实现:
1,A系统生成待办代码
/**
* 生成计划任务归档数据 每15分钟触发一次
*/
@Scheduled(cron = "0 0/1 * * * ?")
public void generatePlanTask() {
// ConstantUtils.ONE 执行类型 manual_generate_plan_task :锁的名字
planTaskArchivingService.generatePlanTask(ConstantUtils.ONE, "manual_generate_plan_task");
}
// Service
@Override
@Transactional(rollbackFor = Exception.class)
public void generatePlanTask(int taskType, String lockName) {
Date currentDate = new Date();
RLock lock = redissonClient.getLock(lockName);
if (lock.isLocked()) {
log.info("当前的时间是:{},锁的名字是:{},", currentDate, lockName + ResultCodeEnum.GENERATE_PLAN_TASK_ERROR.getMessage());
}
lock.lock();
try {
// TODO:业务实现
// TODO: 入库
} catch (Exception e) {
// 日志打印
} finally {
// 释放锁
lock.unlock();
}
2、推送B系统定时任务的实现:
@Scheduled(cron = "0 0/3 * * * ?")
@GetMapping("/autoPushxxxTaskJobHandlerTask")
public void autoPushxxxTaskJobHandlerTask() {
// 今天的开始时间 比如2024-07-09 00:00:00
Date currentDateStart = DateUtils.getAppointedDayStart(0);
// 今天的结束时间 比如2024-07-09 23:59:59
Date currentDateEnd = DateUtils.getAppointedDayEnd(-1);
planTaskxxxService.autoPushxxxTaskJobHandlerTask(currentDateStart, currentDateEnd);
}
// service实现
@Override
public void autoPushxxxTaskJobHandlerTask(Date currentDateStart, Date currentDateEnd)
{
// 查询待办表,组装数据格式 批量推送....
}
开始时候逻辑是上面格式:
可能存在的问题?
1,为什么写2个定时任务,而不是同步推送数据?
答:个人理解,该功能是2个小功能,一个是生成A系统待办,另一个是组装B系统的数据格式推送数据,解耦、单一职责 所以写成2个
2,如果推送数据失败了,会怎么推送哪些指定时间的数据?
答:后面添加了补偿接口,可推送指定时间段的数据,比如B系统挂了3天,我们推送指定时间段的数据。
功能实现:
/**
* 手动补偿接口 ,推送B系统
*
*/
@GetMapping("/manualCompensationPushxxxTask")
public void manualCompensationPushWbsTaskJobHandlerTask(@RequestParam(value = "startDate") String startDate,
@RequestParam(value = "endDate") String endDate) {
planTaskxxxService.manualCompensationPushxxxTask(DateUtils.getStartDate(startDate, DateUtils.DATE_TIME_PATTERN),
DateUtils.getStartDate(endDate, DateUtils.DATE_TIME_PATTERN));
}
3,重复推送的数据,你们是怎么处理的?
答:B系统约束,如果该唯一标识ID就不保存,没有就保存
需求演变2
产品上线后,发现A系统生成数据后,B系统那边也要同步保存数据,不然,会报错,任务ID不存在,A系统和B系统是有交互的。
需求实现:
// A系统的生成待办实现类
@Override
@Transactional(rollbackFor = Exception.class)
public void generatePlanTask(int taskType, String lockName) {
Date currentDate = new Date();
RLock lock = redissonClient.getLock(lockName);
if (lock.isLocked()) {
log.info("当前的时间是:{},锁的名字是:{},", currentDate, lockName + ResultCodeEnum.GENERATE_PLAN_TASK_ERROR.getMessage());
}
lock.lock();
try {
// TODO:业务实现
// TODO: 入库
// 调用组装B系统的信息,推送xxxB系统
autoPushxxxTaskJobHandlerTask(Date currentDateStart, Date currentDateEnd)
} catch (Exception e) {
// 日志打印
} finally {
// 释放锁
lock.unlock();
}
上线调试:
问题描述:
1,现象一:发现A系统数据库保存后,没有推送到B系统
2,现象二:打印日志后发现,调用autoPushxxxTaskJobHandlerTask(Date currentDateStart, Date currentDateEnd);这个接口的时候,没有根据时间范围查询数据。
3,现象三:如果手动触发补偿数据是好的
问题解决:
1,发现 @Transactional(rollbackFor = Exception.class)的问题,我们都知道这个是Spring的事务,是啥呢,用我自己的话了解,在该方法里面,要么都成功,要么都失败,只有再提交事务的时候才会保存数据到数据库。
2,去掉注解后,发现推送数据还是为空,手动可以推送数据,但是在A系统生成待办后,同步推送数据到B系统,查询待办信息为空。推送B系统查询待办信息代码片段如下
@Override
public void autoPushxxxTaskJobHandlerTask(Date currentDateStart, Date currentDateEnd) {
// 1,获取当天的开始时间和结束时间,查询作业归档数据 task_state = 1
// 2.如果作业归档有数据
List<PlanTaskxxxxBo> planTaskxxxxList = planTaskTaskMapper
.queryPlanTaskxxxxByTimeRange(currentDateStart, currentDateEnd);
// 3.封装参数 调用远程接口,批量推送
if (CollectionUtils.isEmpty(planTaskxxxxList )) {
return;
}
.....
问题分析:
如果是手动推送待办信息到B系统,可以根据时间范围查询到待办信息,但是自动不行,是不是时间的问题呢?
最后发现果然是:
A系统生成待办,里面有个创建时间 ,如下
@Override
@Transactional(rollbackFor = Exception.class)
public void generatePlanTask(int taskType, String lockName) {
Date currentDate = new Date();
RLock lock = redissonClient.getLock(lockName);
if (lock.isLocked()) {
log.info("当前的时间是:{},锁的名字是:{},", currentDate, lockName + ResultCodeEnum.GENERATE_PLAN_TASK_ERROR.getMessage());
}
lock.lock();
try {
// TODO:业务实现
// TODO: 入库
// 调用推送B系统的数据接口
autoPushxxxTaskJobHandlerTask(currentDate , null)
} catch (Exception e) {
// 日志打印
} finally {
// 释放锁
lock.unlock();
}
生成时间格式是: Tue Jul 09 10:42:00
但是时间格式是 2024-07-09 00:00:00 才可以根据时间范围查询数据
解决方案:
将 Date currentDate = new Date(); 转换为String类型的时间,然后再转换Date类型,主要是要格式化时间
喜欢我的文章记得点个在看,或者点赞,持续更新中ing…