代码之家  ›  专栏  ›  技术社区  ›  Guerric P

如何为每个计划方法设置一个休眠会话

  •  1
  • Guerric P  · 技术社区  · 6 年前

    我有以下设置:

    @Component
    public class Scheduler {
        Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Autowired
        BatchService batchService;
    
        @Scheduled(cron = "0 */1 * ? * *")
        void tick() {
            logger.info("Beginning of a batch tick");
            batchService.refundNotAssignedVisits();
            logger.info("End of the batch tick");
        }
    }
    

    BatchService 包含以下内容:

    @Service
    public class BatchServiceImpl implements BatchService {
    
        Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Autowired
        VisitService visitService;
    
        @Override
        @Transactional
        public void refundNotAssignedVisits() {
            logger.info("Start automatic refund of past visits being assigned");
    
            Set<Visit> visits = visitService.findRefundableVisits();
    
            if(visits != null && visits.size() != 0) {
                logger.info("Found " + visits.size() + " visits to refund with IDs: " + visits.stream().map(x -> x.getId().toString()).collect(Collectors.joining(", ")));
                visits.forEach(x -> {
                    logger.info("Refunding visit with ID: " + x.getId());
                    try {
                        visitService.cancel(x);
                        logger.info("Visit successfully refunded!");
                    }
                    catch(Exception e) {
                        logger.error("Error while refunding visit...", e);
                    }
                });
            }
            else {
                logger.info("Found no visit to refund.");
            }
    
            logger.info("End of automatic refund");
        }
    }
    

    以及 cancel 方法定义如下:

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public Visit cancel(Visit visit) throws Exception {
        // Some business logic
    }
    

    我需要 取消 方法在每次调用中有一个事务,用于业务目的,并且目前 refundNotAssignedVisits @Transactional 为了启用休眠会话,我可以使用延迟加载来处理 取消 方法。

    这会导致诸如重复提交之类的问题,我想知道什么样的模式才能实现我想要的:有一个 @Scheduled 方法,该方法启用休眠会话,以便对另一个方法进行多个调用,每个调用一个事务。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Ken Chan    6 年前

    @Transactional REQUIRES_NEW 将创建另一个新的休眠会话,因此会话 cancel() 将不同于用于加载对我来说似乎很尴尬的实体的会话。通常,我们使用相同的会话来加载和管理事务中的同一个实体。

    我将把代码重构为以下内容:

    VisitService :

    //Cannel by visitorId and load the Visitor by Id in a new transaction
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public Visit cancel(Integer visitorId) throws Exception {
        Visit visit=  session.get(Visit.class , visitorId); 
        cancel(visit); 
    }
    
    @Override
    public Visit cancel(Visit visit) throws Exception {
        // Some business logic
    }
    
    //Add method to return the IDs only
    @Transactional(readOnly=true)
    public Set<Integer> findRefundableVisitId(){
    
    }
    

    BatchService:

    //@Transactional  (Do not require anymore)
    public void refundNotAssignedVisits() {
        logger.info("Start automatic refund of past visits being assigned");
    
        Set<Integer> refundVisitIds = visitService.findRefundableVisitId();
        refundVisitIds.forEach( id-> {
               try {
                    visitService.refund(id);
                    logger.info("Visit successfully refunded!");
                }
                catch(Exception e) {
                    logger.error("Error while refunding visit...", e);
                }        
         });
    }    
    

    这样,每个退款都是在自己的事务中执行的,用于加载退款的事务访问者不需要等待所有退款完成即可提交,而无需再进行“重复提交”。