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

升级至Spring-tx-5.3+后事务配置调整及TDS协议错误解决

问题描述

将Spring Boot从2.3.12.RELEASE升级至2.4.0及以上版本(对应spring-tx从5.2.15升级至5.3+)后,SQL Server JDBC驱动报出如下错误:

c.m.sqlserver.jdbc.internals.TDS.Reader : TDSReader@30(ConnectionID:1 ClientConnectionId:ff3ee928-1a1c-4d97-b4b7-f13d87f4d35c) got unexpected value in TDS response at offset:7992
c.m.s.jdbc.internals.SQLServerException : *** SQLException:ConnectionID:1 ClientConnectionId:ff3ee928-1a1c-4d97-b4b7-f13d87f4d35c com.microsoft.sqlserver.jdbc.SQLServerException: The TDS protocol stream is not valid. The TDS protocol stream is not valid.

背景信息

代码调用两个存储过程:一个用于在数据库建立应用会话,另一个获取varbinary(max)类型数据。在Spring Boot 2.4.0+版本中,读取该二进制数据的字节时触发上述错误。测试类代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest(classes=CarServiceApplication.class)
@Transactional(propagation = Propagation.NEVER, transactionManager="carTransactionManager")
@Slf4j
public class HoldingRepositoryTest {
    
    @Autowired
    private SessionRepository sessionRepository;
    
    @Autowired
    private CarRepository carRepository;
    
    @Autowired
    private AppProperties appLogin;

    @Test
    public void test() throws SQLException {
        sessionRepository.getSession(appLogin.getUser(), appLogin.getPassword());
        LocalDate july5Of2016 = LocalDate.of(2016, 7, 5);
        Blob reportData = carRepository.getReportData("VIN1234", july5Of2016);
        byte[] reportDataBytes = reportData.getBytes(1, (int) reportData.length()); //error occurs here
        assertThat(reportData, notNullValue());
    }
}

事务管理器配置如下:

@Configuration
@EnableJpaRepositories(basePackages={"com.example.car.repository"}, 
    entityManagerFactoryRef="carEntityManagerFactory",
    transactionManagerRef = "carTransactionManager") 
@EnableJpaAuditing
public class CarDatabaseConfiguration {

    @Bean
    public LocalContainerEntityManagerFactoryBean carEntityManagerFactory(
            EntityManagerFactoryBuilder builder, 
            DataSource dataSource) {       
        return builder
                .dataSource(dataSource)
                .packages("com.example.car.domain")
                .persistenceUnit("car")
                .build();
    }

    @Bean
    public PlatformTransactionManager carTransactionManager(EntityManagerFactory carEntityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(carEntityManagerFactory);
        return transactionManager;
    }

}

已尝试操作

在Spring 2.3.12.RELEASE中移除@Transactional会出现相同的TDS错误,但升级至2.4.0+版本后,该注解似乎被忽略。

核心问题

  1. 如何修改事务配置以避免该错误,恢复至Spring Boot2.3.12.RELEASE版本的运行状态?
  2. 为何将getReportData调用移至服务层方法并添加@Transactional(propagation = Propagation.NEVER, transactionManager="carTransactionManager")(或Propagation.NOT_SUPPORTED)后问题解决?
  3. 为何Spring Boot2.4.0+版本中,测试类的@Transactional注解会被忽略,而服务层方法的该注解可正常生效?

解答

1. 修复事务配置以恢复旧版本运行状态

有两种可行方案:

  • 方案一:调整测试类事务注解
    给测试类的@Transactional添加@Rollback(false),同时确保propagation = Propagation.NEVER配置正确。Spring Boot 2.4+对测试类事务的处理逻辑有调整,默认的回滚机制会干扰连接状态,导致TDS协议解析异常。
  • 方案二:全局配置测试事务行为
    在application-test.properties中添加配置:
    spring.test.transaction.rollback-on-commit-failure=false
    
    或者直接禁用测试类的默认事务管理,确保调用存储过程时没有事务上下文干扰,避免连接被事务管理器复用或状态重置。

2. 服务层添加事务注解解决问题的原因

Propagation.NEVER和Propagation.NOT_SUPPORTED都会强制在无事务上下文的环境下执行代码:

  • Propagation.NEVER:如果当前存在事务则直接抛出异常,确保代码完全脱离事务;
  • Propagation.NOT_SUPPORTED:如果当前存在事务则挂起它,执行完后再恢复。

建立应用会话的存储过程可能会修改连接的会话状态(比如设置特定的上下文参数),而事务上下文会复用连接或重置连接状态,导致后续读取varbinary(max)数据时,TDS协议流的状态不一致。将getReportData放到服务层并添加这两种传播级别的注解,会让该方法在独立的无事务连接中执行,避免了事务对连接状态的干扰,从而解决TDS解析错误。

3. Spring Boot2.4+测试类事务注解被忽略的原因

这是因为Spring Boot 2.4+对@SpringBootTest的事务处理逻辑做了优化:

  • 旧版本(2.3.x)中,测试类的@Transactional会直接覆盖默认的测试事务配置;
  • 新版本(2.4+)中,@SpringBootTest默认启用了测试事务管理器的自动配置,会优先使用内置的测试事务逻辑,导致测试类上自定义的@Transactional(尤其是指定了自定义事务管理器和传播级别)被忽略。

而服务层的@Transactional不受此影响,因为它是由业务层的事务切面处理,和测试类的事务管理逻辑相互独立,所以能正常生效。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:05:39