在使用Transaction事务的方法中,catch到异常并手动进行事务回滚。

本文探讨了使用Quartz进行定时任务时遇到的问题,即在方法中加入事务控制后,异常被捕获但事务未能正常回滚的情况。文章详细介绍了如何通过手动设置事务回滚或抛出RuntimeException来解决此问题。

今天在做使用Quartz进行定时更新数据操作时,发现在加了事务的方法在try{}catch{}捕获异常的时候,事务无法进行回滚

这个是添加事务的接口:

  /**
     * 更新实时数据
     */
    @Transactional
    public Map<String,Object> batchAddHik();

 

实现类捕获异常代码块:

/**
     * 定时批量更新数据
     */
    @Override
    public Map<String,Object> batchAddHik() {
        //..
        Map<String,Object> map = new HashMap<String, Object>(); 
     final List<Object[]> insertParams = new ArrayList<Object[]>();
        for (ClInout clInout : clInouts) {
            String plateNo = clInout.getPlateNo();
            String crossTime = clInout.getCrossTime();
            Integer releaseMode = clInout.getReleaseMode();
            Integer vehicleSize = clInout.getVehicleSize();
            Integer carOut = clInout.getCarOut();
            String platePicUrl = clInout.getPlatePicUrl() == null ? "" : clInout.getPlatePicUrl();
            String vehiclePicUrl = clInout.getVehiclePicUrl() == null ? "" : clInout.getVehiclePicUrl();
            String facePicUrl = clInout.getFacePicUrl() == null ? "" : clInout.getFacePicUrl();
            String hikRecordUuid = clInout.getHikRecordUuid();

            insertParams.add(new Object[] {plateNo,crossTime,releaseMode,vehicleSize,carOut,platePicUrl,vehiclePicUrl,facePicUrl,hikRecordUuid});
        }

        String sql = "INSERT INTO cl_inout (plate_no, cross_time, release_mode, vehicle_size, car_out, plate_pic_url, vehicle_pic_url, face_pic_url, hik_record_uuid)"
                + "VALUES (?,?,?,?,?,?,?,?,?)";

        if (clInouts.size() > 0) {

            try {
                num = this.getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() {
                    @Override
                    public void setValues(PreparedStatement ps, int i) throws SQLException { 
                        Object[] args = insertParams.get(i);
                        ps.setString(1, (String) args[0]);
                        ps.setString(2, (String) args[1]);
                        ps.setInt(3, (Integer) args[2]);
                        ps.setInt(4, (Integer) args[3]);
                        ps.setInt(5, (Integer) args[4]);
                        ps.setString(6, (String) args[5]);
                        ps.setString(7, (String) args[6]);
                        ps.setString(8, (String) args[7]);
                        ps.setString(9, (String) args[8]);
                    }

                    @Override
                    public int getBatchSize() {
                        return insertParams.size();
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
                String message = e.getMessage();
                map.put("exception", message);
                map.put("number", 0);

            }

        }
    //..
}   

此时,在batchUpdate过程若catch到异常,事务将无法回滚,程序依然会将部分插入到数据库中。

解决办法:

spring在捕获RuntimeException异常后,才会进行事务回滚。

故,在catch代码块中,添加:

} catch (Exception e) {
                e.printStackTrace();
                String message = e.getMessage();
                map.put("exception", message);
                map.put("number", 0);
                // 手动设置当前事务回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                // 或者手动抛出runTimeException
//                throw new RuntimeException();
            }

 

这样,便能让事务回滚了又捕获到异常了。

 

转载于:https://www.cnblogs.com/libera11/p/8054072.html

在Spring事务中,异常try - catch捕获后是否会回滚需要分情况来看: - **默认情况**:如果使用try - catch把整个业务方法包裹起来,没有任何异常从业务方法中抛出,全被捕获“吞掉”,会导致Spring异常抛出触发事务回滚策略失效,事务不会回滚。例如在service方法使用try - catch捕获异常且不抛出,就脱离了Spring事务的管理,事务不会回滚。若想让事务回滚,可在catch语句中最后增加`throw new RuntimeException()`语句,以便让AOP捕获异常再去回滚且在service上层(controller)要继续捕获这个异常处理;或者在catch语句中增加`TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()`语句,手动回滚,这样上层就无需去处理异常 [^1][^4]。 - **运行时异常**:在Spring等框架中,默认情况下,运行时异常(`RuntimeException`及其子类)会导致事务回滚。即使在try - catch中捕获了这些异常,如果没有显式地调用事务的提交方法(在大多数场景下,框架会管理事务),事务管理器仍然会根据异常的类型和配置来决定是否回滚事务 [^2]。 - **`@Transactional`注解情况**:Spring事务注解`@Transactional`本来可保证原子性,若事务报错,整个事务回滚,但加上try - catch或者事务嵌套,可能会导致事务回滚失败 [^3]。 下面是一个示例代码,展示了不同处理方式下的事务回滚情况: ```java import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; @Service public class TransactionService { @Transactional public void noRollbackExample() { try { // 模拟数据库操作 // ... throw new RuntimeException("模拟运行时异常"); } catch (RuntimeException e) { // 异常被捕获,没有重新抛出,事务不会回滚 } } @Transactional public void rollbackWithThrow() { try { // 模拟数据库操作 // ... throw new RuntimeException("模拟运行时异常"); } catch (RuntimeException e) { throw new RuntimeException(e); // 重新抛出异常事务回滚 } } @Transactional public void rollbackManually() { try { // 模拟数据库操作 // ... throw new RuntimeException("模拟运行时异常"); } catch (RuntimeException e) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); // 手动回滚事务 } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值