springboot @Transaction注解失效之谜

使用注解@Transaction声明式事务时,遇到了失效的问题,简要记录,以备后患。

确保已开启TransactionManagment,让你的注解生效

  • 如果你的项目引入了boot-starter的jbdc或jpa包,则不需要自己配置DataSourceTransactionManager,boot自动配置特性会帮你配置,
  • 如果未正确配置,则需在Application启动类上,使用注解@EnableTransactionManagement让springboot帮你配置
  • 不建议重写config类,自己实现改配置

确保使用正确的声明式注解@Transactional

springframework下的注解包类名全称:org.springframework.transaction.annotation.Transactional

确保注解作用域的方法修饰符

  • @Transaction作用于类上,则该类下的所有public方法生效
  • @Transaction作用于方法上,只有public修饰的方法生效,其余不生效
  • @Transaction最好作用于类/或类的的方法上,而不是接口/或接口的方法上,因为作用于接口上你必须保证使用的是JDK动态代理而不是CGLB代理
    来自springboot官网的解释:

The Spring team recommends that you annotate only concrete classes (and methods of concrete classes) with the @Transactional annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method), but this works only as you would expect it to if you use interface-based proxies. The fact that Java annotations are not inherited from interfaces means that, if you use class-based proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj"), the transaction settings are not recognized by the proxying and weaving infrastructure, and the object is not wrapped in a transactional proxy, which would be decidedly bad.

确保调用的是Aop代理类方法而不是目标方法

@Transaction注解基于Aop代理生效,所以只有再使用代理类的带有注解的方法才会生效。比如,方法内 调用同类含有@Transaction注解的其他方法,则执行的是目标类方法(本类方法),而不是代理类的方法,所以不会生效

确保@Transaction的回滚异常

  • 手动try/catch吃掉异常,显然不会回滚
  • 未正确声明回滚/不回滚的异常类型,注解默认回滚RuntimeException和Error,其他查询异常不会回滚,可以使用@Transaction的rollbackFor和noRollbackFor属性设置异常类型

确保数据库表引擎支持事务

使用JPA的spring.jpa.hibernate.ddl-auto配置自动创建的表,默认引擎是engine=MyISAM,是不支持事务的,使用JPA要注意这点,建议不要打开自动创建表配置。
查看/修改数据库表引擎的命令:

show create TABLE customer;

CREATE TABLE `customer` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `address` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `phone` varchar(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=38 DEFAULT CHARSET=utf8

ALTER TABLE customer ENGINE = INNODB;

多数据源使用EntityManager执行update/delete时,保证EntityManager的类型是PersistenContextType. TRANSACTION

使用em.createQuery()执行update/delete时,有可能会发生Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query;
意思是 执行query需要事务,请检查以下配置:

  @Autowired
  @Qualifier("otherEm") //别名
  @PersistenceContext  //默认PersistenContextType. TRANSACTION,必须设置TRANSACTION(这里设置后,下面代码不需要entityManager.joinTransaction())
  private EntityManager entityManager;

  @Override
  @Transactional(transactionManager = "transactionManagerBos")  //指定em
  public void save(User user, Article article) {
    entityManager.joinTransaction();//若果没有使用PersistenceContext指定em类型,则需要开启加入事务
    entityManager.createNativeQuery("insert into user (age) values (1);").executeUpdate();
  }

------------或者声明em时候加入--------
 @Bean(name = "otherEm")
  public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
    EntityManager em = entityManagerFactoryBos(builder).getObject().createEntityManager();
    em.joinTransaction();
    return em;
  }
@PersistenceContext或者em.joinTransaction();

(PS:通过将@PersistenceContext 注解标注在EntityManager 类型的字段上,这样得到的EntityManager 就是容器管理的EntityManager 。由于是容器管理的,所以我们不需要也不应该显式关闭注入的EntityManager 实例。

容器管理的EntityManager 又细分为两种类型:事务范围(Transaction )的和扩展的(Extended )。

若@PersistenceContext 未指定type 属性,或者指定为PersistenContextType.TRANSACTION ,则表示该EntityManager 是事务范围的;若指定为PersistenContextType.EXTENDED 的,则表示该EntityManager 是扩展的。
事务范围:事务范围的EntityManager 是无状态的,可用在无状态会话Bean 和有状态会话Bean 中。
事务范围的EntityManager 依赖于JTA 事务,每次调用EntityManager 实例的相关方法时,EntityManager 会查看是否有某个持久化上下文与当前事务关联,如果有,则使用该持久化上下文;如果没有,则EntityManager 将创建一个持久化上下文,并将该持久化上下文与当前事务关联。当事务结束,则持久化上下文消失。
扩展的:扩展的EntityManager 只能用于有状态会话Bean 。
扩展的EntityManager 在有状态会话Bean 实例创建的时候创建一个持久化上下文,并且直到该有状态会话Bean 销毁,则相应的持久化上下文才被移除。
由于在扩展的EntityManager 中,每次方法调用都是使用的相同的持久化上下文,所以前一次方法调用时产生的受管实体在下一个方法访问时仍然为受管实体)


以上就是常遇到的几个问题,后续开发在遇到类似问题,持续更新!
文章如有不正之处请联系作者进行修改,万分感谢!
微信:


springboot @Transaction注解失效之谜_第1张图片
weixin

你可能感兴趣的:(springboot @Transaction注解失效之谜)