@Transactional 的注解问题

@Transactional 注解使用场景详细说明包括(不生效的场景,事务回滚) 阅读详情

接手新项目一言难尽,别的不说单单就一个 @Transactional 注解用的一塌糊涂,五花八门的用法,很大部分还失效无法回滚。

图片

有意识的在涉及事务相关方法上加@Transactional注解,是个好习惯。不过,很多同学只是下意识地添加这个注解,一旦功能正常运行,很少有人会深入验证异常情况下事务是否能正确回滚。@Transactional 注解虽然用起来简单,但这货总是能在一些你意想不到的情况下失效,防不胜防!

我把这些事务问题归结成了三类:不必要、不生效、不回滚,接下用一些demo演示下各自的场景。

不必要

1. 无需事务的业务

在没有事务操作的业务方法上使用 @Transactional 注解,比如:用在仅有查询或者一些 HTTP 请求的方法,虽然加上影响不大,但从编码规范的角度来看还是不够严谨,建议去掉。

@Transactional
public String testQuery() {
    standardBak2Service.getById(1L);
    return "testB";
}

2. 事务范围过大

有些同学为了省事直接将 @Transactional 注解加在了类上或者抽象类上,这样做导致的问题就是类内的方法或抽象类的实现类中所有方法全部都被事务管理。增加了不必要的性能开销或复杂性,建议按需使用,只在有事务逻辑的方法上加@Transactional。

@Transactional
public abstract class BaseService {
}

@Slf4j
@Service
public class TestMergeService extends BaseService{

    private final TestAService testAService;

    public String testMerge() {

        testAService.testA();

        return "ok";
    }
}

如果在类中的方法上添加 @Transactional 注解,它将覆盖类级别的事务配置。例如,类级别上配置了只读事务,方法级别上的 @Transactional 注解也会覆盖该配置,从而启用读写事务。

@Transactional(readOnly = true)
public class TestMergeService {

    private final TestBService testBService;

    private final TestAService testAService;

    @Transactional
    public String testMerge() {

        testAService.testA();

        testBService.testB();
        return "ok";
    }
}    

不生效

3. 方法权限问题

不要把 @Transactional注解加在 private 级别的方法上!

我们知道 @Transactional 注解依赖于Spring AOP切面来增强事务行为,这个 AOP 是通过代理来实现的,而 private 方法恰恰不能被代理的,所以 AOP 对 private 方法的增强是无效的,@Transactional也就不会生效。

@Transactional
private String testMerge() {

    testAService.testA();

    testBService.testB();

    return "ok";
}

那如果我在 testMerge() 方法内调用 private 的方法事务会生效吗?

答案:事务会生效

@Transactional
public String testMerge() throws Exception {

    ccc();
    
    return "ok";
}

private void ccc() {
    testAService.testA();

    testBService.testB();
}

4. 被用 final 、static 修饰方法

和上边的原因类似,被用 final 、static 修饰的方法上加 @Transactional 也不会生效。

  • static 静态方法属于类本身的而非实例,因此代理机制是无法对静态方法进行代理或拦截的

  • final 修饰的方法不能被子类重写,事务相关的逻辑无法插入到 final 方法中,代理机制无法对 final 方法进行拦截或增强。

这些都是java基础概念了,使用时要注意。

@Transactional
public static void b() {
}

@Transactional
public final void b() {
}

5. 同类内部方法调用问题

注意了,这种情况经常发生啊!

同类内部方法间的调用是 @Transactional 注解失效的重灾区,网上你总能看到方法内部调用另一个同类的方法时,这种调用是不会经过代理的,因此事务管理不会生效。但这说法比较片面,要分具体情况。

比如:testMerge() 方法开启事务,调用同类非事务的方法 a() 和 b() ,此时 b() 抛异常,根据事务的传播性 a()、b() 事务均生效。

@Transactional
public String testMerge() {

    a();

    b();

    return "ok";
}

public void a() {
    standardBakService.save(testAService.buildEntity());
}

public void b() {
    standardBak2Service.save(testBService.buildEntity2());
    throw new RuntimeException("b error");
}

如果 testMerge() 方法未开启事务,并且在同类中调用了非事务方法 a() 和事务方法 b(),当 b() 抛出异常时,a() 和 b() 的事务都不会生效。因为这种调用直接通过 this 对象进行,未经过代理,因此事务管理无法生效。这经常出问题的!

public String testMerge() {

    a();

    b();

    return "ok";
}

public void a() {
    standardBakService.save(testAService.buildEntity());
}

@Transactional
public void b() {
    standardBak2Service.save(testBService.buildEntity2());
    throw new RuntimeException("b error");
}
5.1 独立的 Service 类

要想 b() 方法的事务生效也容易,最简单的方法将它剥离放在独立的Service类注入使用,交给spring管理就行了。不过,这种方式会创建很多类。

@Slf4j
@Service
public class TestBService {

      @Transactional
      public void b() {
          standardBak2Service.save(testBService.buildEntity2());
          throw new RuntimeException("b error");
      }
}
5.2 自注入方式

或者通过自己注入自己的方式解决,尽管解决了问题,逻辑看起来很奇怪,它破坏了依赖注入的原则,虽然 spring 支持我们这样用,还是要注意下循环依赖的问题。

@Slf4j
@Service
public class TestMergeService {
      @Autowired
      private TestMergeService testMergeService;

      public String testMerge() {

          a();

          testMergeService.b();

          return "ok";
      }

      public void a() {
          standardBakService.save(testAService.buildEntity());
      }

      @Transactional
      public void b() {
          standardBak2Service.save(testBService.buildEntity2());
          throw new RuntimeException("b error");
      }
}
5.3 手动获取代理对象

b() 方法它不是没被代理嘛,那我们手动获取代理对象调用 b() 方法也可以。通过 AopContext.currentProxy() 方法返回当前的代理对象实例,这样调用代理的方法时,就会经过 AOP 的切面,@Transactional注解就会生效了。

@Slf4j
@Service
public class TestMergeService {

      public String testMerge() {

          a();

         ((TestMergeService) AopContext.currentProxy()).b();

          return "ok";
      }

      public void a() {
          standardBakService.save(testAService.buildEntity());
      }

      @Transactional
      public void b() {
          standardBak2Service.save(testBService.buildEntity2());
          throw new RuntimeException("b error");
      }
}

6. Bean 未被 spring 管理

上边我们知道 @Transactional 注解通过 AOP 来管理事务,而 AOP 依赖于代理机制。因此,Bean 必须由Spring管理实例! 要确保为类加上如 @Controller、@Service 或 @Component注解,让其被Spring所管理,这很容易忽视。

@Service
public class TestBService {

    @Transactional
    public String testB() {
        standardBak2Service.save(entity2);
        return "testB";
    }
}

7. 异步线程调用

如果我们在 testMerge() 方法中使用异步线程执行事务操作,通常也是无法成功回滚的,来个具体的例子。

testMerge() 方法在事务中调用了 testA(),testA() 方法中开启了事务。接着,在 testMerge() 方法中,我们通过一个新线程调用了 testB(),testB() 中也开启了事务,并且在 testB() 中抛出了异常。

此时的回滚情况是怎样的呢?

@Transactional
public String testMerge() {

    testAService.testA();

    new Thread(() -> {
        try {
            testBService.testB();
        } catch (Exception e) {
//                e.printStackTrace();
            throw new RuntimeException();
        }
    }).start();

    return "ok";
}

@Transactional
public String testB() {
    DeepzeroStandardBak2 entity2 = buildEntity2();

    dataImportJob2Service.save(entity2);

    throw new RuntimeException("test2");
}

@Transactional
public String testA() {
    DeepzeroStandardBak entity = buildEntity();
    standardBakService.save(entity);
    return "ok";
}

答案是:testA() 和 testB() 中的事务都不会回滚。

testA() 无法回滚是因为没有捕获到新线程中 testB()抛出的异常;testB()方法无法回滚,是因为事务管理器只对当前线程中的事务有效,因此在新线程中执行的事务不会回滚。

由于在多线程环境下,Spring 的事务管理器不会跨线程传播事务,事务的状态(如事务是否已开启)是存储在线程本地的 ThreadLocal 来存储和管理事务上下文信息。这意味着每个线程都有一个独立的事务上下文,事务信息在不同线程之间不会共享。

8. 不支持事务的引擎

不支持事务的数据库引擎不在此次 Review 范围内,只做了解就好。我们通常使用的关系型数据库,如 MySQL,默认使用支持事务的 InnoDB 引擎,而非事务的 MyISAM 引擎则使用较少。

以前开启启用 MyISAM 引擎是为了提高查询效率。不过,现在非关系型数据库如 Redis、MongoDB 和 Elasticsearch 等中间件提供了更高性价比的解决方案。

不回滚

9. 用错传播属性

@Transactional注解有个关键的参数propagation,它控制着事务的传播行为,有时事务传播参数配置错误也会导致事务的不回滚。

propagation 支持 7 种事务传播特性:

  • REQUIRED:默认的传播行为,如果当前没有事务,则创建一个新事务;如果存在事务,则加入当前事务。

  • MANDATORY:支持当前事务,如果不存在则抛出异常

  • NEVER:非事务性执行,如果存在事务,则抛出异常

  • REQUIRES_NEW:无论当前是否存在事务,都会创建一个新事务,原有事务被挂起。

  • NESTED:嵌套事务,被调用方法在一个嵌套的事务中运行,这个事务依赖于当前的事务。

  • SUPPORTS:如果当前存在事务,则加入;如果没有,就以非事务方式执行。

  • NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,将其挂起。

为了加深印象,我用案例来模拟下每种特性的使用场景。

REQUIRED

REQUIRED 是默认的事务传播行为。如果 testMerge() 方法开启了事务,那么其内部调用的 testA() 和 testB() 方法也将加入这个事务。如果 testMerge() 没有开启事务,而 testA() 和 testB() 方法上使用了 @Transactional 注解,这些方法将各自创建新的事务,只控制自身的回滚。

@Component
@RequiredArgsConstructor
@Slf4j
@Service
public class TestMergeService {

    private final TestBService testBService;

    private final TestAService testAService;

    @Transactional
    public String testMerge() {

        testAService.testA();

        testBService.testB();

        return "ok";
    }
}

@Transactional
public String testA() {
    log.info("testA");
    DeepzeroStandardBak entity = buildEntity();
    standardBakService.save(entity);
    return "ok";
}

@Transactional
public String testB() {
    log.info("testB");
    DeepzeroStandardBak2 entity2 = buildEntity2();
    standardBak2Service.save(entity2);
    throw new RuntimeException("testB");
}
MANDATORY

MANDATORY 传播特性简单来说就是只能被开启事务的上层方法调用,例如 testMerge() 方法未开启事务调用 testB() 方法,那么将抛出异常;testMerge() 开启事务调用 testB() 方法,则加入当前事务。

@Component
@RequiredArgsConstructor
@Slf4j
@Service
public class TestMergeService {

    private final TestBService testBService;

    private final TestAService testAService;

    public String testMerge() {

        testAService.testA();

        testBService.testB();

        return "ok";
    }
}

@Transactional
public String testA() {
    log.info("testA");
    DeepzeroStandardBak entity = buildEntity();
    standardBakService.save(entity);
    return "ok";
}

@Transactional(propagation = Propagation.MANDATORY)
public String testB() {
    log.info("testB");
    DeepzeroStandardBak2 entity2 = buildEntity2();
    standardBak2Service.save(entity2);
    throw new RuntimeException("testB");
}

抛出的异常信息

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

NEVER

NEVER 传播特性是强制你的方法只能以非事务方式运行,如果方法存在事务操作会抛出异常,我实在是没想到有什么使用场景。

@Transactional(propagation = Propagation.NEVER)
public String testB() {
    log.info("testB");
    DeepzeroStandardBak2 entity2 = buildEntity2();
    standardBak2Service.save(entity2);
//        throw new RuntimeException("testB");
    return "ok";
}

抛出的异常信息

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

REQUIRES_NEW

我们在使用 Propagation.REQUIRES_NEW 传播特性时,不论当前事务的状态如何,调用该方法都会创建一个新的事务。

例如,testMerge() 方法开始一个事务,调用 testB() 方法时,它会暂停 testMerge() 的事务,并启动一个新的事务。如果 testB() 方法内部发生异常,新事务会回滚,但原先挂起的事务不会受影响。这意味着,挂起的事务不会因为新事务的回滚而受到影响,也不会因为新事务的失败而回滚。

@Transactional
public String testMerge() {

    testAService.testA();

    testBService.testB();

    return "ok";
}

@Transactional
public String testA() {
    log.info("testA");
    DeepzeroStandardBak entity = buildEntity();
    standardBakService.save(entity);
    return "ok";
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public String testB() {
    log.info("testB");
    DeepzeroStandardBak2 entity2 = buildEntity2();
    standardBak2Service.save(entity2);
    throw new RuntimeException("testB");
}
NESTED

方法的传播行为设置为 NESTED,其内部方法会开启一个新的嵌套事务(子事务)。在没有外部事务的情况下 NESTED 与 REQUIRED 效果相同;存在外部事务的情况下,一旦外部事务回滚,它会创建一个嵌套事务(子事务)。

也就是说外部事务回滚时,子事务会跟着回滚;但子事务的回滚不会对外部事务和其他同级事务造成影响。

@Component
@RequiredArgsConstructor
@Slf4j
@Service
public class TestMergeService {

    private final TestBService testBService;

    private final TestAService testAService;

    @Transactional
    public String testMerge() {

        testAService.testA();

        testBService.testB();

        throw new RuntimeException("testMerge");
        return "ok";
    }
}

@Transactional
public String testA() {
    log.info("testA");
    DeepzeroStandardBak entity = buildEntity();
    standardBakService.save(entity);
    return "ok";
}

@Transactional(propagation = Propagation.NESTED)
public String testB() {
    log.info("testB");
    DeepzeroStandardBak2 entity2 = buildEntity2();
    standardBak2Service.save(entity2);
    throw new RuntimeException("testB");
}
NOT_SUPPORTED

NOT_SUPPORTED 事务传播特性表示该方法必须以非事务方式运行。当方法 testMerge() 开启事务并调用事务方法 testA() 和 testB() 时,如果 testA() 和 testB() 的事务传播特性为 NOT_SUPPORTED,那么 testB() 将以非事务方式运行,并挂起当前的事务。

默认传播特性的情况下 testB() 异常事务加入会导致 testA() 回滚,而挂起的意思是说,testB() 其内部一旦抛出异常,不会影响 testMerge() 中其他 testA() 方法的回滚。

@Component
@RequiredArgsConstructor
@Slf4j
@Service
public class TestMergeService {

    private final TestBService testBService;

    private final TestAService testAService;

    @Transactional
    public String testMerge() {

        testAService.testA();

        testBService.testB();

        return "ok";
    }
}

@Transactional
public String testA() {
    log.info("testA");
    DeepzeroStandardBak entity = buildEntity();
    standardBakService.save(entity);
    return "ok";
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public String testB() {
    log.info("testB");
    DeepzeroStandardBak2 entity2 = buildEntity2();
    standardBak2Service.save(entity2);
    throw new RuntimeException("testB");
}
SUPPORTS

如果当前方法的事务传播特性是 SUPPORTS,那么只有在调用该方法的上层方法开启了事务的情况下,该方法的事务才会有效。如果上层方法没有开启事务,那么该方法的事务特性将无效。

例如,如果入口方法 testMerge() 没有开启事务,而 testMerge() 调用的方法 testA() 和 testB() 的事务传播特性为 SUPPORTS,那么由于 testMerge() 没有事务,testA() 和 testB() 将以非事务方式执行。即使在这些方法上加上 @Transactional 注解,也不会回滚异常。

@Component
@RequiredArgsConstructor
@Slf4j
@Service
public class TestMergeService {

    private final TestBService testBService;

    private final TestAService testAService;

    public String testMerge() {

        testAService.testA();

        testBService.testB();

        return "ok";
    }
}

@Transactional(propagation = Propagation.SUPPORTS)
public String testA() {
    log.info("testA");
    DeepzeroStandardBak entity = buildEntity();
    standardBakService.save(entity);
    return "ok";
}

@Transactional(propagation = Propagation.SUPPORTS)
public String testB() {
    log.info("testB");
    DeepzeroStandardBak2 entity2 = buildEntity2();
    standardBak2Service.save(entity2);
    throw new RuntimeException("testB");
}

10. 自己吞了异常

在整个 review 的过程中我发现导致事务不回滚的场景,多数是开发同学在业务代码中手动 try...catch 捕获了异常,然后又没抛出异常....

比如:testMerge() 方法开启了事务,并调用了非事务方法 testA() 和 testB(),同时在 testMerge() 中捕获了异常。如果 testB() 中发生了异常并抛出,但 testMerge() 捕获了这个异常而没有继续抛出,Spring 事务将无法捕获到异常,从而无法进行回滚。

@RequiredArgsConstructor
@Slf4j
@Service
public class TestMergeService {

    private final TestBService testBService;

    private final TestAService testAService;
    @Transactional
    public String testMerge() {

        try {
            testAService.testA();

            testBService.testB();

        } catch (Exception e) {
            log.error("testMerge error:{}", e);
        }
        return "ok";
    }
}

@Service
public class TestAService {

    public String testA() {
        standardBakService.save(entity);
        return "ok";
    }
}

@Service
public class TestBService {

    public String testB() {
        standardBakService.save(entity2);
        
        throw new RuntimeException("test2");
    }
}

为了确保 Spring 事务能够正常回滚,需要我们在 catch 块中主动重新抛出它能够处理的 RuntimeException 或者 Error 类型的异常。

@Transactional
public String testMerge() {

    try {
        testAService.testA();

        testBService.testB();

    } catch (Exception e) {
        log.error("testMerge error:{}", e);
        throw new RuntimeException(e);
    }
    return "ok";
}

捕获异常并不意味着一定不会回滚,这取决于具体情况。

例如,当 testB() 方法上也加上了 @Transactional 注解时,如果在该方法中发生异常,事务会捕获到这个异常。由于事务传播的特性,testB() 的事务会合并到上层方法的事务中。因此,即使在 testMerge() 中捕获了异常而未抛出,事务仍然可以成功回滚。

@Transactional
public String testB() {

    DeepzeroStandardBak2 entity2 = buildEntity2();

    dataImportJob2Service.save(entity2);

    throw new RuntimeException("test2");
    // return "ok";
}

但这有个提前,必须在 testMerge() 方法上添加 @Transactional 注解以启用事务。如果 testMerge() 方法没有开启事务,不论其内部是否使用 try 块,都只能部分回滚 testB(),而 testA() 将无法回滚。

11. 事务无法捕获的异常

Spring 的事务默认会回滚 RuntimeException 及其子类,以及 Error 类型的异常。

如果抛出的是其他类型的异常,例如 checked exceptions(检查型异常),即继承自 Exception 但不继承自 RuntimeException 的异常,比如 SQLException、DuplicateKeyException,事务将不会回滚。

所以,我们在主动抛出异常时,要确保该异常是事务能够捕获的类型。

@Transactional
public String testMerge() throws Exception {
    try {
        testAService.testA();

        testBService.testB();
    } catch (Exception e) {
        log.error("testMerge error:{}", e);
//            throw new RuntimeException(e);
        throw new Exception(e);
    }
    return "ok";
}

如果你非要抛出默认情况下不会导致事务回滚的异常,务必要在 @Transactional 注解的 rollbackFor 参数中明确指定该异常,这样才能进行回滚。

@Transactional(rollbackFor = Exception.class)
public String testMerge() throws Exception {
    try {
        testAService.testA();

        testBService.testB();
    } catch (Exception e) {
        log.error("testMerge error:{}", e);
//            throw new RuntimeException(e);
        throw new Exception(e);
    }
    return "ok";
}

问问你身边的同学,哪些异常属于运行时异常,哪些属于检查型异常,十有八九他们可能无法给出准确的回答!

所以减少出现 bug 的风险,我建议使用 @Transactional 注解时,将 rollbackFor 参数设置为 Exception 或 Throwable,这样可以扩大事务回滚的范围。

12. 自定义异常范围问题

针对不同业务定制异常类型是比较常见的做法,@Transactional 注解的 rollbackFor 参数支持自定义的异常,但我们往往习惯于将这些自定义异常继承自 RuntimeException。

那么这就出现和上边同样的问题,事务的范围不足,许多异常类型仍然无法触发事务回滚。

@Transactional(rollbackFor = CustomException.class)
public String testMerge() throws Exception {
    try {
        testAService.testA();

        testBService.testB();
    } catch (Exception e) {
        log.error("testMerge error:{}", e);
//            throw new RuntimeException(e);
        throw new Exception(e);
    }
    return "ok";
}

想要解决这个问题,可以在 catch 中主动抛出我们自定义的异常。

@Transactional(rollbackFor = CustomException.class)
public String testMerge() throws Exception {
    try {
        testAService.testA();

        testBService.testB();
    } catch (Exception e) {
        log.error("testMerge error:{}", e);
        throw new CustomException(e);
    }
    return "ok";
}

13. 嵌套事务问题

还有一种场景就是嵌套事务问题,比如,我们在 testMerge() 方法中调用了事务方法 testA() 和事务方法 testB(),此时不希望 testB() 抛出异常让整个 testMerge() 都跟着回滚;这就需要单独 try catch 处理 testB() 的异常,不让异常在向上抛。

@RequiredArgsConstructor
@Slf4j
@Service
public class TestMergeService {

    private final TestBService testBService;

    private final TestAService testAService;
    @Transactional
    public String testMerge() {
    
        testAService.testA();

        try {
            testBService.testB();
        } catch (Exception e) {
            log.error("testMerge error:{}", e);
        }
        return "ok";
    }
}

@Service
public class TestAService {

    @Transactional
    public String testA() {
        standardBakService.save(entity);
        return "ok";
    }
}

@Service
public class TestBService {

    @Transactional
    public String testB() {
        standardBakService.save(entity2);
        
        throw new RuntimeException("test2");
    }
}

总结

上面的关于 @Transactional 注解的使用注意事项是我在代码审查和搜集网络观点后整理出的。之前我也写过类似的文章,但当时内容不够全面。这次的补充更为详尽,涵盖了更多细节。开发工作只是整体工作量的一小部分,更多时间实际上花在了自测和验证上。希望这些案例对大家有所收获,少踩坑。

从FER2013到AffectNet:表情识别数据集十年演进史与你的项目选型攻略 本文回顾了从FER2013到AffectNet等主流人脸表情识别数据集的十年演进历程,详细分析了各数据集的特点、适用场景及技术突破。针对不同项目需求,提供了从移动端应用到高精度研究的选型策略,特别强调AffectNet在现代FER项目中的核心价值,并给出混合数据集构建的实战方案。 阅读详情

相关推荐

ADS SerDes仿真实战:深入解析Tx_Diff均衡器(EQ)参数对眼图质量的影响

本文以ADS仿真平台为基础,深入解析了SerDes设计中Tx_Diff均衡器(EQ)参数对信号完整性的核心影响。通过实战演示,详细对比了去加重(De-emphasis)与FIR抽头系数两种调节模式,揭示了它们如何有效对抗信道损耗与码间干扰,从而显著改善眼图的高度、宽度与抖动性能,为高速串行链路设计提供关键调优思路。

weixin_29230901的博客 228

@Transactional注解超详细

Transactional注解是Spring框架中用于声明式事务管理的关键注解。本文将深入探讨@Transactional注解的作用、使用方式和常见属性,并结合代码实例演示其在实际项目中的应用,以帮助读者更好地理解和使用该注解。@Transactional注解是Spring框架中用于声明式事务管理的关键注解。通过使用@Transactional注解,我们可以更加方便地管理事务,保障数据的一致性和可靠性。在实际项目中,合理使用@Transactional注解可以提高「开发效率 」和代码「可维护性 」。

Wzill 3万+

SAP ERP销售应收&成本科目确定

ERP作为业财一体软件,其中最核心的就是业务与财务模块的自动集成,无需财务进行手工做账,提高工作效率的同时降低人工操作产生的误差。今天浅浅的分享一下SD模块生成会计凭证时,借贷项确定的系统配置。一般项目上借贷项、科目都有FICO提供,但是具体的集成配置是在SD这边。

weixin_43657667的博客 1569

@Transactional 注解

@Transactional 注解相信大家并不陌生,平时开发中很常用的一个注解,它能保证方法内多个数据库操作要么同时成功、要么同时失败。使用@Transactional注解时需要注意许多的细节,不然你会发现@Transactional总是莫名其妙的就失效了。 一、事务 事务管理在系统开发中是不可缺少的一部分,Spring提供了很好事务管理机制,主要分为编程式事务和声明式事务两种。 1、编程式事务 是指在代码中手动的管理事务的提交、回滚等操作,代码侵入性比较强。 编程式事务方式需要开发者在代码中手动的管理事务

csdnlaiyanqi的博客 5万+

开关电源设计实战:如何用AP值快速选型磁芯(附计算公式推导)

本文为开关电源工程师提供了基于AP值的磁芯快速选型实战指南。文章深入解析了AP值作为磁芯‘功率吞吐量’指标的核心物理意义,并通过详细的公式推导和24W反激电源设计实例,手把手演示如何利用AP值计算公式,结合电流密度、窗口利用率等关键参数,从众多磁芯型号中高效筛选出合适型号,同时强调了选型后的关键校验步骤与常见误区。

weixin_29234239的博客 878

LVS 负载均衡面试题及参考答案

什么是 LVS 负载均衡?它的主要作用是什么? LVS(Linux Virtual Server)是一个基于 Linux 内核的开源负载均衡项目。它通过将请求流量按照一定的算法分发到后端的多个真实服务器(Real Server)上,从而实现负载均衡的功能。 从原理上来说,LVS 工作在网络层和传输层之间。当客户端发起请求时,请求首先到达 LVS 服务器,LVS 会根据预先设定的规则和算法,比如轮询(Round - Robin)、加权轮询(Weighted Round - Robin)、最少连

大模型大数据攻城狮的专栏 1469

@Transactional注解的使用范围

@Transactional注解的使用范围

shilaiyin8288的博客 4579

再不入坑就晚了,深度神经网络概念大整理,最简单的神经网络是什么样子?

再不入坑就晚了,深度神经网络概念大整理,最简单的神经网络是什么样子?

我是香菜 3万+

@Transactional属性详解

文章目录@Transactional属性详解使用说明注解失效问题@Transactional 应用在非 public 修饰的方法上@Transactional 注解属性 rollbackFor 设置错误同一个类中方法调用,导致@Transactional失效异常被你的 catch“吃了”导致@Transactional失效数据库引擎不支持事务开启多线程任务时,事务管理会受到影响 @Transactional属性详解 声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或

棉花糖的博客 3614

PCIe协议之 Equalization篇 之 谈谈几种模式

对于两端有能力最高支持 32 GT/s 及以上速率的设备,如果把目标速度设置为 8 GT/s 或 16 GT/s 速率,是不建议采用 Bypass-Equalization-to-Highest-Rate 模式的,即便采用了,也不会针对 8 GT/s 或 16 GT/s 的目标速率进行 EQ。对于支持 32 GT/s 及以上速率的设备,其可能根本无需工作在 8 GT/s 或 16 GT/s 速率,这时再针对 8 GT/s 或 16 GT/s 速率进行 EQ,多少有点浪费。

那么菜的博客 567

B站自动答题协议分析

使用Python写了一个自动答题机器人!基于接口协议实现且包含点选验证码识别

吴秋霖的博客 2658

@Transactional 注解与synchronized的使用的一些实战问题

@Transactional注解与synchronized使用带来的一些问题 这几天在练习写一个小工程,遇到了一些问题,代码大致如下: @RequestMapping(value = "/downCodeFile",method = RequestMethod.POST) @Transactional public String downCode(HttpServletRe...

海棠花未眠的博客 1541

【WRF-UCM】BEP+BEM 模拟:README

【WRF-UCM】BEP+BEM 模拟:README

WW、forever的博客 223

@Transactional注解失效问题

总结一下: 1,同一个类中的方法调用,被调用的方法事务无效,aop的自调用问题 2,方法try catch发生异常,catch不处理是不会回滚的,抛出RuntimeException可以回滚 ...

qq_41725999的博客 231

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

使用@Transactional注解事务,可能出现哪些问题呢

前言 在之前的文章中已经对Spring中的事务做了详细的分析了,这篇文章我们来聊一聊平常工作时使用事务可能出现的一些问题(本文主要针对使用@Transactional进行事务管理的方式进行讨论)以及对应的解决方案 事务失效 事务回答相关问题 读写分离跟事务结合使用时的问题 事务失效 事务失效我们一般要从两个方面排查问题 数据库层面 数据库层面,数据库使用的存储引擎是否支持事务?默认情况下MySQL数据库使用的是Innodb存储引擎(5.5版本之后),它是支持事务的,但是如果你的表特地修改了存储引擎,例

weixin_39098944的博客 752

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

@Transactional事务及@Async注解问题

1. 你们有用@Transactional来控制事务是吧,那么能不能说出一些事务不生效的场景? 不生效的场景 数据库引擎是否支持事务(MySql的MyISAM引擎不支持事务) @Transactional 注解属性 rollbackFor 设置错误 rollbackFor 可以指定能够触发事务回滚的异常类型。Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望

2594

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

java中事物的注解_Java注解@Transactional事务类内调用不生效问题及解决办法

@Transactional 内部调用例子 ????在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会造成自调用问题。若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务被忽略,不会发生回滚@Servicepublic class ...

weixin_35878217的博客 844

关于@Transactional注解失效的问题以及注意点

原文:https://zhuanlan.zhihu.com/p/114390589

此人很懒,什么也没有留下~ 435

关于@Transactional注解失效的问题

deepseek的结论和chatgpt结论完全相反,但是我的项目确实按照豆包和gpt的方法解决了。最近开发项目时,@Transactional注解失效,在网上查了各种解决方法,都解决不了问题。chatGPT 的结论是neo4j影响了springboot配置默认的事务管理器。配置类中加上上面的代码后@Transactional注解可以正常使用了。我想到了我的项目中用到了neo4j。希望有大佬能解释一下。

m0_52816220的博客 227

关于 @Transactional 注解导致找不到表的问题分析

关于 @Transactional 注解导致找不到表的问题分析

// 471

@Transactional注解事务不回滚问题 不生效

一、需求场景:service类中循环插入数据,希望只回滚抛异常的记录,不抛异常的正常入库。 伪代码: @Service public class A{ public void a(){ for(Obj obj : list){ b(obj); } } @Transactional(rollbackFor = Exception.class) void a(Obj obj){ save(obj) } } 以上代码运行后发现事务不回滚,原因是:同一个类中,非@Transactional注解调用@Transact

haifei0926的专栏 3645

@Transactional 注解失效问题

1. @Transactional 注解添加在非 public 修饰的方法上; 2. @Transactional 的 propagation 属性设置问题; TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。 TransactionDefinit

qq_38152400的博客 577

@Transactional注解使用及同时使用try catch导致注解失效问题

Transactional注解使用及使用try catch导致Transactional失效问题

qq_65642052的博客 2206

@Transactional注解失效,基于注解的切面失效问题

轮到我了哈哈,最近在测接口的时候发现@Transactional标记的方法事务没有生效,问了同事是说与动态代理有关,于是我复习了一下,顺便做个记录。

qq_52886103的博客 800
上一篇: WebSocket 在SpringBoot 的 3 种集成方式!!
下一篇: 弃用 Nginx,他们选择这款工具!
架构文摘JGWZ
博客等级 码龄5年 8808粉丝 345原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值