spring中,大事务问题

2023-04-05  本文已影响0人  同吢欢楽

上一次,和朋友们聊了聊事务失效场景,我已经整理成了文章,Java开发中,导致事务失效的场景。紧接着有提到了大事务问题,经过一番激烈的讨论,对这个问题也算是有了一些输出场景。下面我简要描述一下。

一、概念

什么是大事务?简要来说就是:运行时间比较长,操作的数据比较多的事务。

二、大事务引发的问题

大事务对系统来说,是导致响应缓慢的一个重要原因。它会引发一些列问题,诸如:锁等待、死锁、接口超时、数据库主从延迟、事务回滚时间长、数据库连接池被占满等问题。

三、形成原因或解决办法

1. 将查询放到事务外处理。

@Transactional(rollbackFor=Exception.class)

   public void save(Entity entity) {

         selectData();

         addData(entity );

         updateData(entity );

   }

如上代码所示,一个事务中,同事包含了查询,新增,修改,这种时候,就容易出现大事务。当然,改造也很简单,把查询的放到事务外。这里就要引入另一种事务实现方式:编程式事务。上述代码是:声明式事务。

@Autowired

privateTransactionTemplate transactionTemplate;

public void save(Entity entity) {

    selectData();

      transactionTemplate.execute((obj) => {

          addData(entity );

         updateData(entity );

         returnBoolean.TRUE;

      })

}

2.尽量少用声明式事务@Transactional

我相信这种事务使用场景应该是非常广泛的,包括我所参与的项目中,使用这样的方式来配置事务占有率也是非常高的,但是为什么会建议少使用这种方式呢?

2.1 我们都知道,spring事务其实就是通过aop切面来起作用的,如果使用不当,会使得事务失效,详见我的上一篇文章。

2.2 这种事务声明,一般是用于业务代码中的某个方法,这种方法内,往往可能存在多种数据库操作,这种时候,就容易产生大事务,如上述例子。解决方法依然是:使用编程式事务来管控。

3.事务中,存在RPC调用

在事务中,如果使用了外部的远程调用、内部业务调用、MQ或Redis等,因为调用过程中的不可控的网络延迟因素,导致大事务发生或产生异常导致事务回滚。

@Transactional(rollbackFor=Exception.class)

   public void save(Entity entity) {

        feignClient.read();

        redisTemplate.get();

         addData();

   }

解决办法依然是,把需要添加事务的部分,添加事务,最常用的依然是编程式事务。

@Autowired

privateTransactionTemplate transactionTemplate;

public void save(Entity entity) {

      feignClient.read();

      redisTemplate.get();

      transactionTemplate.execute((obj) => {

         addData();

         updateData();

         returnBoolean.TRUE;

      })

}

4.异步处理

如果在业务逻辑中,需要做多步骤、多阶段操作或消息发送等,我们可以采取异步操作来处理这部分事情。把事务尽量做到精确化。

@Autowired

privateTransactionTemplate transactionTemplate;

public void save(Entity entity) {

      transactionTemplate.execute((obj) => {

         addData(entity);

         returnBoolean.TRUE;

      })

      sendMessage();

}
上一篇 下一篇

猜你喜欢

热点阅读