记录@Transactional和Date时间引起推送数据失败

@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…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值