编程式事务 (Java)

编程式事务
开始 :

Spring可以支持编程式事务和声明式事务。
Spring提供的最原始的事务管理方式是基于TransactionDefinition、PlatformTransactionManager、TransactionStatus 编程式事务。
TransactionTemplate的编程式事务管理是使用模板方法设计模式对原始事务管理方式的封装。

为什么要使用编程式事务?

编程式事务是一种在数据库操作中使用的事务处理方式,通过编写程序来控制事务的提交或回滚。与声明式事务相比,编程式事务需要手动指定事务的启动、提交和回滚等操作,具有更精细的控制能力。

以下是一些使用编程式事务的优点:

灵活性: 编程式事务可以根据业务逻辑和数据操作的复杂度进行灵活的控制和处理,保证数据的一致性和完整性;

可读性: 编程式事务代码可以直接显示了事务的边界和执行顺序,方便理解和调试;

安全性: 使用编程式事务可以防止数据库死锁和数据冲突等问题,在多并发访问中保障数据的安全和可靠性;

跨框架支持: 编程式事务可以跨框架地使用,不依赖于任何特定的框架或容器,使得开发人员可以自由地选择合适自己的工具进行开发和部署;

增量修改: 使用编程式事务时,可以控制每个事务的大小和影响范围,因此在大型系统需求变化频繁的情况下很有用,能够更方便地新增或修改系统的某些功能,而不会对整个系统造成影响。

当然,使用编程式事务也有一些缺点,如代码冗长、可维护性差等问题,需要在使用时权衡利弊并根据业务需求选择最佳的事务处理方式。

个人是因为业务需求原因而选择了它,举例如下:

// 原代码
@Transactional(rollbackFor = Exception.class)
public Boolean alterOperation(Object obj){
    
    
// 查询操作1
object1 = service.select();
// 数据处理
.......
// 查询操作2
object2 = service.select2();
// 查询操作3
object3 = service.select3();
.....
// 此处省略查询操作与逻辑......

// 最后增删改操作.....
boolean rs = update();
}

我们可以看到上面方法使用注解开启了事务,并且是一个相对较长的事务,整个方法做了大量的查询等逻辑操作,如果查询很复杂,时查询时长较长加剧对系统资源和性能的影响.所以在这尽量缩短事务执行的时间,让其他查询可以更快的获得资源和锁.
我们现在可以做的就是:

拆分长事务:我们应该尽可能将一个长过程拆分为多个短小的事务,确保每个事务只关注它所需的数据和逻辑,避免将不必要的其他资源锁定在事务中;

降低事务隔离级别:将隔离级别从最高级别(如Serializable)降低到更低的级别(如Read Committed),可以减少锁的数量和范围,提高并发性能,但也可能会带来数据一致性问题,需要评估风险进行决策;

使用乐观锁:在更新记录时,我们可以使用乐观锁技术,即先读取记录并将其版本号或时间戳等信息保存在变量中,然后进行修改时检查该记录是否被其他事务更新过,如果没有就执行更新操作。这种方式可以避免使用悲观锁占用太多资源

合理设计数据库架构:合理的表设计和索引设计能够减小锁的粒度,启用分区表或者sharding也可以使得数据无需跨越多个节点查询。


下面使用编程式事务来拆分长事务

基础使用: 减少事务粒度,防止查询长时间阻塞.

# 引用注入 事务模板
@Autowired
private TransactionTemplate transactionTemplate;

# 在需要添加事务方法里编写代码
public Boolean test(){
    
    
    // 各种查询代码
    // 开启事务
    Boolean rs = transactionTemplate.execute(transactionStatus -> {
    
    
        return Boolean.TRUE; 或者 return Boolean.FALSE;
    }
}

所以当我们借助TransactionTemplate.execute( … )执行事务管理的时候,传入的参数有两种选择:
1、TransactionCallback
2、TransactionCallbackWithoutResult

两种区别从命名看就相当明显了,一个是有返回值,一个是无返回值。这个的选择就取决于你是读还是写了。

例子:
借助(TransactionCallback)执行事务管理,既带有返回值:

public Object getObject(String str) {
    
    
        /*
         *  执行带有返回值<Object>的事务管理
         */
        transactionTemplate.execute(new TransactionCallback<Object>() {
    
    
            @Override
            public Object doInTransaction(TransactionStatus transactionStatus) {
    
    
                try {
    
    
                      ...
                    //.......   业务代码
                    return new Object();
                } catch (Exception e) {
    
    
                    //回滚
                    transactionStatus.setRollbackOnly();
                    return null;
                }
            }
        });
}

借助(TransactionCallbackWithoutResult)执行事务管理,既无返回值:

public void update(String str) {
    
    

         /*
         *  执行无返回值的事务管理
         */
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    
    
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
    
    

                try {
    
    

                    // ....  业务代码
                } catch (Exception e){
    
    
                    //回滚
                    transactionStatus.setRollbackOnly();
                }

            }
        });
}

猜你喜欢

转载自blog.csdn.net/AKALXH/article/details/130170484
今日推荐