编程式事物TransactionTemplate

1.简介

TransactionTemplate 是 Spring 框架中用于编程式事务管理的工具类。它简化了事务管理的代码,允许你在代码中显式地控制事务的边界。

1. TransactionTemplate 的主要方法

 execute 方法:

	public <T> T execute(TransactionCallback<T> action) throws TransactionException {
		Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

		if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager cpptm) {
			return cpptm.execute(this, action);
		}
		else {
			TransactionStatus status = this.transactionManager.getTransaction(this);
			T result;
			try {
				result = action.doInTransaction(status);
			}
			catch (RuntimeException | Error ex) {
				// Transactional code threw application exception -> rollback
				rollbackOnException(status, ex);
				throw ex;
			}
			catch (Throwable ex) {
				// Transactional code threw unexpected exception -> rollback
				rollbackOnException(status, ex);
				throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
			}
			this.transactionManager.commit(status);
			return result;
		}
	}

作用: 执行带有返回值的事务操作。

参数: TransactionCallback<T> 是一个函数式接口,它包含一个 doInTransaction(TransactionStatus status) 方法,你可以在该方法中编写需要在事务中执行的代码。

返回值: 返回 T 类型的值,即事务操作的结果。

TransactionTemplate transactionTemplate = SpringUtils.getBean(TransactionTemplate.class);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
String result = transactionTemplate.execute(status -> {
    try {
        // 执行业务逻辑
        return someService.someMethod();
    } catch (Exception e) {
        // 触发事务回滚
        status.setRollbackOnly();
        throw new ServiceException("业务执行失败: " + e.getMessage());
    }
});
2.配置方法

TransactionTemplate 还提供了一些配置方法,用于设置事务的传播行为、隔离级别、超时时间等:

setPropagationBehavior(int propagationBehavior): 设置事务的传播行为,例如 PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW 等。

setIsolationLevel(int isolationLevel): 设置事务的隔离级别,例如 ISOLATION_READ_COMMITTED、ISOLATION_SERIALIZABLE 等。

setTimeout(int timeout): 设置事务的超时时间(以秒为单位)。

setReadOnly(boolean readOnly): 设置事务是否为只读事务。

分别对应声明式事物@Transactional中的对应属性;

3. 常见问题与注意事项

事务回滚

  • 默认回滚规则: 默认情况下,Spring 只会在遇到 RuntimeException ,Error和 Throwable时回滚事务。如果你希望在遇到检查异常(checked exception)时也回滚事务,可以通过 status.setRollbackOnly() 手动设置回滚。

  • 手动回滚: 在 execute 方法中,如果捕获到异常并希望回滚事务,可以调用 status.setRollbackOnly()

  • 多次平行调用execute方法,被视为不同的事物,传播行为仅生效在嵌套事务的情况下。下附单元测试概述。

    public void testExecute() {
        Long entityId = 1888854477837537282L;

        // 初始化数据
        entityMapper.update(Wrappers.lambdaUpdate(Entity.class)
            .eq(Entity::getId, entityId )
            .set(Entity::getRemark, "initial remark"));

        // 设置传播行为为 PROPAGATION_REQUIRED
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);

        try {
            // 第一次更新(成功)
            transactionTemplate.execute(status1 -> {
                subtaskMapper.update(Wrappers.lambdaUpdate(Entity.class)
                    .eq(Entity::getId, entityId )
                    .set(Entity::getRemark, "remark 1st"));
                return null;
            });

            // 第二次更新(抛出异常)
            transactionTemplate.execute(status2 -> {
                subtaskMapper.update(Wrappers.lambdaUpdate(Entity.class)
                    .eq(Entity::getId, subtaskId)
                    .set(Entity::getRemark, "remark 2nd"));
                //或者设置回滚
                status2.setRollbackOnly();
                return null;
            });
        } catch (Exception e) {
            // 捕获异常,但不处理
        }

        // 验证数据是否回滚
        Entity entity= entityMapper.selectById(entityId );
        if (Objects.equals("initial remark", entity.getRemark())) {
            log.info("数据应回滚到初始状态");
        }
        log.info("数据当前状态:{}", entity.getRemark());

        //输出数据-->数据当前状态:remark 1st
    }

    public void testRequired() {
        Long entityId = 1888854477837537282L;

        // 初始化数据
        entityMapper.update(Wrappers.lambdaUpdate(Entity.class)
            .eq(Entity::getId, entityId )
            .set(Entity::getRemark, "initial remark"));

        // 设置传播行为为 PROPAGATION_REQUIRED
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);

    try {
        // 外层事务
        transactionTemplate.execute(status -> {
            // 第一次更新(在同一个事务中)
            subtaskMapper.update(Wrappers.lambdaUpdate(TmsSubtask.class)
                    .eq(TmsSubtask::getId, subtaskId)
                    .set(TmsSubtask::getRemark, "remark 1st"));

            // 第二次更新(嵌套在同一个事务中)
            transactionTemplate.execute(status2 -> {
                subtaskMapper.update(Wrappers.lambdaUpdate(TmsSubtask.class)
                        .eq(TmsSubtask::getId, subtaskId)
                        .set(TmsSubtask::getRemark, "remark 2nd"));
                throw new RuntimeException("模拟异常");
            });

            return null;
        });
    } catch (Exception e) {
        // 捕获异常
    }

        // 验证数据是否回滚
        Entity entity= entityMapper.selectById(entityId );
        if (Objects.equals("initial remark", entity.getRemark())) {
            log.info("数据应回滚到初始状态");
        }
        log.info("数据当前状态:{}", entity.getRemark());

        //输出数据-->数据当前状态:initial remark
    }

事务传播行为

  • 传播行为的选择: 根据业务需求选择合适的传播行为。例如,PROPAGATION_REQUIRED 表示如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

  • 嵌套事务: 如果你需要嵌套事务,可以使用 PROPAGATION_NESTED,但要注意数据库和事务管理器是否支持嵌套事务。

事务隔离级别

  • 隔离级别的选择: 根据业务需求选择合适的隔离级别。例如,ISOLATION_READ_COMMITTED 可以避免脏读,但可能会遇到不可重复读和幻读问题。

事务超时

  • 超时设置: 如果事务执行时间过长,可能会导致数据库锁争用或资源耗尽。可以通过 setTimeout 方法设置事务的超时时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值