使用@Transactional 程序里面添加了try{}catch{}中事务就不回滚

    @Transactional
    public void splitExcuteSql(String sqlStr) {
        // 去掉\t\n\r等内容
        String[] split = sqlStr.split(";");
        List<String> sqlList = new ArrayList<>(Arrays.asList(split));

        String excuteSql;
        try {
            for (String sql : ListUtils.emptyIfNull(sqlList)) {
                if (StringUtils.isNotBlank(sql)) {
//                    executeSqls(sql.trim()); // 执行sql
                }
            }
        } catch (Exception e) {
            String message = e.getMessage();
            if (message.contains("PRIMARY")) {
                message = message + " 主键重复,请增大序列当前值,再进行插入!";
            }
            // 手动回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new RuntimeException(message);
        }
    }

为什么呢?因为方法上未加任何属性的@Transactional注解只能在抛出RuntimeException或者Error时才会触发事务的回滚,常见的非RuntimeException是不会触发事务的回滚的。

 如果要在抛出 非RuntimeException时也触发回滚机制,需要我们在注解上添加 rollbackFor = { Exception.class }属性。

使用@Transactional(rollbackFor = { Exception.class }),抛出捕获的非RuntimeException异常
方法上使用@Transactional(rollbackFor = { Exception.class })注解声明事务回滚级别,在捕获到异常时在catch语句中直接抛出所捕获的异常。

/**
     *  分离sql和执行sql
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void splitExcuteSql(String sqlStr) {
        // 去掉\t\n\r等内容
        String repalceSqlStr = replaceSpecialBlank(sqlStr);
        String[] split = sqlStr.split(";");
        List<String> sqlList = new ArrayList<>(Arrays.asList(split));
        
        String excuteSql;
        try {
            for (String sql : ListUtils.emptyIfNull(sqlList)) {
                if (StringUtils.isNotBlank(sql)) {
//                    executeSqls(sql.trim()); // 执行sql
                }
            }
        } catch (Exception e) {
            String message = e.getMessage();
            if (message.contains("PRIMARY")) {
                message = message + " 主键重复,请增大序列当前值,再进行插入!";
            }
            // 手动回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new RuntimeException(message);
        }

    }

    // 去掉 回车、换行符、制表符
    private String replaceSpecialBlank(String str) {
        String dest = "";
        if (str != null) {
            Pattern p = Pattern.compile("[\t\r\n]");
            Matcher m = p.matcher(str);
            dest = m.replaceAll(" ");
        }
        return dest;
    }

上面代码包括了处理方式:

1,@Transactional(rollbackFor = { Exception.class }),抛出捕获的非RuntimeException异常

2, 手动回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

3,抛出运行时异常:throw new RuntimeException(message);

总结:

如果这三种方式都不管用的时候,可以在调用该方法的方法,加@Transactional

@Transactional
public void uploadSqlFile(MultipartFile file, String oper, String createType) throws Exception {
    String sqlStr = replaceUploadSql(file, createType);
    splitExcuteSql(sqlStr);
}

在上一个方法添加@Transactional,不管调用的方法如何,有报错就会执行回滚。也就不用管是否加了try{}catch{}。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐