You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用HibernateTransactionManager时@Transactional(REQUIRES_NEW)无法创建新事务

Spring @Transactional(Propagation.REQUIRES_NEW) 不生效问题排查

问题背景

正在重构遗留代码,将Spring配置从XML迁移至Java类配置。已通过TransactionConfiguration.java初始化事务管理器,应用可正常读写数据库,但在只读事务中调用标注@Transactional(propagation = Propagation.REQUIRES_NEW)的方法时,无法创建新事务。此前使用XML配置TransactionProxyFactoryBean时该功能正常。

相关配置代码

Java类配置(TransactionConfiguration.java)

@Configuration
@EnableTransactionManagement
public class TransactionConfiguration
{
  private String[] packagesToScan = {...redacted...};

  @Bean
  public DataSource dataSource(@Value("${db.driverClassName}") String driverClassName, @Value("${db.url}") String jdbcUrl,
          @Value("${db.usr.login}") String username, @Value("${db.usr.password}") String pwd, @Value("${db.maxPoolSize}") int maxPoolSize)
  {
    HikariDataSource dataSource = new HikariDataSource();
    dataSource.setDriverClassName(driverClassName);
    dataSource.setJdbcUrl(jdbcUrl);
    dataSource.setUsername(username);
    dataSource.setPassword(pwd);
    dataSource.setMaximumPoolSize(maxPoolSize);
    return dataSource;
  }

  @Bean
  public LocalSessionFactoryBean sessionFactory(DataSource dataSource, @Value("${db.schema}") String dbSchema, @Value("${db.dialect}") String dbDialect,
          @Value("${db.show.sql}") Boolean dbShowSql, @Value("${db.hbm2ddl.auto}") String hbm2dll)
  {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(dataSource);
    sessionFactory.setPackagesToScan(packagesToScan);

    Properties hibernateProperties = new Properties();
    hibernateProperties.put("hibernate.default_schema", dbSchema);
    hibernateProperties.put("hibernate.dialect", dbDialect);
    hibernateProperties.put("hibernate.show_sql", dbShowSql);
    hibernateProperties.put("hibernate.hbm2ddl.auto", hbm2dll);

    sessionFactory.setHibernateProperties(hibernateProperties);

    return sessionFactory;
  }

  @Bean
  public PlatformTransactionManager transactionManager(LocalSessionFactoryBean sessionFactory)
  {
    HibernateTransactionManager transactionManager = new HibernateTransactionManager();
    transactionManager.setSessionFactory(sessionFactory.getObject());
    return transactionManager;
  }
}

服务调用场景

@Service
public class Service1{

  @Autowired
  private Service2 service2;

  @Transactional(readOnly = true)
  public void method1()
  {
    [... read only treatment...]

    service2.method2();

    [... read only treatment...]
  }

}

@Service
public class Service2{

  @Autowired
  private Service3 service3;

  
  public void method2()
  {
    [... read only treatment...]

    method3();

    [... read only treatment...]
  }

  private void method3()
  {
    [... read only treatment...]

    service3.method4();

    [... read only treatment...]
  }

}

@Service
public class Service3{

  @Value("${my.test.prop}")
  private String myTestProp;

  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void method4()
  {
    System.out.println(myTestProp);    

    [... write treatment...]
  }

}

原XML配置(正常工作)

<bean class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager" ref="transactionManager" />
        <property name="transactionAttributes">
            <props>
                <prop key="method1">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="method2">PROPAGATION_REQUIRES_NEW</prop>
            </props>
        </property>
    </bean>

已尝试的排查步骤

  • 确认方法分属不同类,保证Spring AOP代理生效
  • 开启Logback日志,未发现新事务创建的日志记录
  • 尝试切换至JPATransactionManager,问题依旧
  • 尝试使用Propagation.NESTED传播行为,未解决问题
  • 环境版本:Spring 5.3.6,Hibernate 5.4.33

问题分析与解决方案

1. 事务管理器配置错误

当前transactionManager Bean的参数是LocalSessionFactoryBean,直接调用getObject()获取SessionFactory会绕过Spring的Bean生命周期管理,可能导致SessionFactory未被正确初始化或代理。正确做法是将参数改为SessionFactory,Spring会自动注入LocalSessionFactoryBean生成的SessionFactory实例:

@Bean
public PlatformTransactionManager transactionManager(SessionFactory sessionFactory)
{
  HibernateTransactionManager transactionManager = new HibernateTransactionManager();
  transactionManager.setSessionFactory(sessionFactory);
  return transactionManager;
}

2. 包扫描范围遗漏

检查TransactionConfiguration中的packagesToScan是否包含Service3所在的包。如果Service3不在扫描范围内,Spring无法识别其@Transactional注解,不会生成事务代理。

3. 事务代理模式问题

@EnableTransactionManagement默认使用JDK动态代理(proxyTargetClass=false),如果Service3没有实现任何接口,需要设置proxyTargetClass=true强制使用CGLIB代理:

@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
public class TransactionConfiguration {
    // ... 其他配置
}

4. 日志级别不足

将Spring事务相关日志级别设为DEBUG,查看是否有事务拦截器的执行日志,确认method4是否被事务切面处理:

<!-- Logback配置示例 -->
<logger name="org.springframework.transaction" level="DEBUG"/>
<logger name="org.springframework.aop.framework" level="DEBUG"/>

内容的提问来源于stack exchange,提问作者TonioLeParigo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 06:55:34