Traversée de boucle de Java, comment s'assurer que chaque corps de boucle est une transaction distincte ?

Je ne sais pas si vous avez rencontré une situation similaire dans le processus de développement proprement dit : par exemple, il existe une telle tâche chronométrée, et certaines commandes qui n'ont pas été payées pour les heures supplémentaires doivent être traitées régulièrement. Ensuite, vous interrogez tous les enregistrements éligibles (en supposant qu'il y a 10 enregistrements), puis la boucle for traverse chaque commande, et chaque corps de boucle doit effectuer un grand nombre d'activités, telles que le retour des stocks de marchandises, la modification du statut de la commande, l'ajout de flux commerciaux, le message pousser etc

Vous avez exécuté avec succès les cinq premières boucles, mais lorsque vous exécutez la sixième boucle, une exception est soudainement levée, ce qui entraîne l'annulation de vos cinq commandes précédentes réussies. Il y a une sorte de bataille de Chibi dans les Trois Royaumes. Lianzhou, le sentiment d'être à la fois prospère et blessé, n'est-ce pas très douloureux ?

La solution est en fait très simple. Il suffit d'un ou deux morceaux de code pour le résoudre. Je l'ai personnellement testé et cela a fonctionné. La façon dont je l'ai testé à l'époque était la suivante : 10 enregistrements ont été interrogés et une exception s'est produite au 6e Une fois les 10 boucles terminées, il s'avère que seul le 6ème enregistrement reste tel quel (la transaction est annulée lorsqu'une exception se produit), tandis que les 5 enregistrements précédents et les 4 enregistrements suivants sont exécutés normalement et ne sont pas affectés .

Mon projet utilise le framework ssm et utilise les tâches de synchronisation fournies avec spring.Le pseudocode suivant commence :

La première est la classe OrderTimer.java : cette classe consiste à obtenir tous les enregistrements qui répondent aux exigences, c'est-à-dire à obtenir cette collection, puis à commencer à parcourir et à exécuter chaque enregistrement qui répond aux exigences. Notez que l'exécution spécifique de l'entreprise doit être encapsulé dans une autre méthode, c'est-à-dire encapsulé dans le traitement de la couche métier, non seulement à cause de la spécification du code, mais surtout parce qu'il est encapsulé dans une autre méthode, de sorte que les propriétés de propagation de la transaction peuvent être définies plus librement.

package demo;
 
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
import java.util.List;
 
@Component
public class OrderTimer {
 
    private static Logger logger = Logger.getLogger(OrderTimer.class);
 
    @Autowired
    private OrderService orderService;
 
    @Autowired
    private OrderMapper orderMapper;
 
    /**
     * 每隔1分钟执行未付款订单的关闭的操作
     */
    @Scheduled(cron = "0 0/1 * * * ?")
    public void closeOrders() {
        logger.info("--------开始每隔1分钟执行未付款订单的关闭的操作");
 
        //获取所有超时未付款的订单,这个需要根据你自己的实际情况编写,此处只是举例
        List<Order> list= orderMapper.listCloseOrder();
        if(list==null||list.size()<1){
            return ;
        }
 
        for (Order order : list) {
            orderService.closeOrder(order);
        }
    }
 
}

Voici le code de la couche d'implémentation, en se concentrant sur deux "préoccupations":

package demo;
 
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
 
@Service
public class OrderServiceImpl implements OrderService {
 
    private static Logger logger=Logger.getLogger(OrderServiceImpl.class);
 
    @Autowired
    private OrderMapper orderMapper;
 
  /**
  这个注解很重要,意思是设置当前方法的事务传播级别为REQUIRES_NEW,表示当前方法内的所有事务都是独立的,不影响整体的事务。
  有的项目使用注解的方式配置当前方法传播属性会无效,此时可能需要你去你的spring-mybatis.xml文件中配置,效果是一样的
  */
    @Transactional(propagation = Propagation.REQUIRES_NEW)//关注点一!!!
    @Override
    public void closeOrder(Order order) {
 
        try{
 
  //这里,执行你自己的业务,比如商品库存回退,订单状态改变,操作流水等。
  //重点关注的是@Transactional注解和TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
    
 
            
        }catch (Exception e){
            logger.info("网络异常:"+e.getMessage());
            
            //这一段表示手动回滚事务,此处的try-catch,是表示当前方法如果出错了,
            //那我就自己消化这个异常,不再往外抛,处理异常的方式是手动回滚事务。
            //如此,每个循环体都自己处理自己的事务,不管成功与失败,都不影响整个循环
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//关注点二!!!
        }
 
    }
 
 
}

La logique générale est la suivante. Ce genre de chose ne peut pas partager des codes spécifiques, car lorsqu'il s'agit de transactions, il doit y avoir des opérations de base de données, et s'il y a des opérations de base de données, vous devez créer des bases de données et des tables. Il est impossible d'écrire tout C'est difficile pour tout le monde, il est donc préférable d'omettre le cœur de métier spécifique, de se concentrer uniquement sur quelques points qui nécessitent une attention particulière, puis de le mettre en œuvre en fonction de votre projet existant et de le tester vous-même.

Bien sûr, comme il s'agit de pseudo-code, il faut des personnes avec une certaine quantité de code pour compenser.

おすすめ

転載: blog.csdn.net/zhangjiaming_zjm/article/details/129754573