Spring Boot 2.7.1 R2DBC在H2 MSSQL兼容模式下findById报LIMIT语法错误
问题说明
将基于Spring Boot 2.6.9开发的应用升级至2.7.x版本线(当前使用2.7.1)时,测试阶段采用开启MS SQL Server兼容模式的H2内存数据库,调用ReactiveCrudRepository的findById方法会抛出SQL语法错误,错误提示生成的查询语句末尾包含MSSQL不支持的LIMIT 2子句。
- 2.6.9版本下相同代码与配置测试执行正常
- 2.7.1版本下执行
./mvnw clean test可稳定复现问题
核心配置与代码如下:
- 测试环境
application.yml配置
spring: r2dbc: url: r2dbc:h2:mem:///testdb?options=MODE=MSSQLServer;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
- 初始化脚本
schema.sql
CREATE SCHEMA IF NOT EXISTS [dbo]; CREATE TABLE IF NOT EXISTS [dbo].[CUSTOMER] ( id INTEGER GENERATED BY DEFAULT AS IDENTITY, name VARCHAR(255) NOT NULL, CONSTRAINT PK__otp__D444C58FB26C6D28 PRIMARY KEY (id) );
- 实体类定义
@Table("[dbo].[CUSTOMER]") @Data @NoArgsConstructor @AllArgsConstructor public class CustomerEntity { @Id @Column("id") private Integer id; @Column("name") private String name; }
- Repository接口定义
public interface CustomerRepository extends ReactiveCrudRepository<CustomerEntity, Integer> { }
- 触发异常的测试代码
@SpringBootTest @RequiredArgsConstructor @TestConstructor(autowireMode = ALL) class BootH2ApplicationTests { private final CustomerRepository customerRepository; @Test void shouldSaveAndLoadUsers() { CustomerEntity joe = customerRepository.save(new CustomerEntity(null, "Joe")).block(); customerRepository.findById(joe.getId()).block(); } }
抛出的核心异常:
Caused by: io.r2dbc.spi.R2dbcBadGrammarException: Syntax error in SQL statement "SELECT [dbo].[CUSTOMER].* FROM [dbo].[CUSTOMER] WHERE [dbo].[CUSTOMER].id = $1 [*]LIMIT 2"; SQL statement: SELECT [dbo].[CUSTOMER].* FROM [dbo].[CUSTOMER] WHERE [dbo].[CUSTOMER].id = $1 LIMIT 2 [42000-214]
根因分析
异常来自Spring Data R2DBC的方言识别逻辑变更:
- Spring Boot 2.6.x绑定的Spring Data R2DBC 1.5.x版本,单条查询自动添加行数限制时,可正确识别H2的MSSQL兼容模式,生成SQL Server支持的
TOP 2语法 - Spring Boot 2.7.x绑定的Spring Data R2DBC 2.0.x版本,R2DBC方言自动检测逻辑未读取到H2连接的兼容模式参数,默认使用H2原生方言,生成了MSSQL模式不支持的
LIMIT子句,最终触发语法错误。
该问题不属于H2数据库缺陷,是框架方言识别逻辑的适配问题。
修复方案
方案1:配置文件强制指定MSSQL方言(推荐)
无需修改业务代码,直接在测试配置中跳过方言自动检测,强制使用SQL Server方言,修改application.yml即可:
spring: r2dbc: url: r2dbc:h2:mem:///testdb?options=MODE=MSSQLServer;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE properties: dialect: mssql
配置生效后,框架生成单条查询时会自动拼接TOP 2语法,完全适配H2的MSSQL兼容模式。
方案2:手动注册方言Bean
如果配置指定方言不生效,可以在测试配置类中手动注册SQL Server方言Bean覆盖默认实现:
@Configuration public class R2dbcTestConfig { @Bean public R2dbcDialect r2dbcDialect() { return SqlServerDialect.INSTANCE; } }
方案3:升级驱动版本
旧版本r2dbc-h2驱动未向上层上报兼容模式对应的数据库类型,将H2、r2dbc-h2升级到最新稳定版可修复自动识别逻辑:
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>test</scope> <version>2.1.214</version> </dependency> <dependency> <groupId>io.r2dbc</groupId> <artifactId>r2dbc-h2</artifactId> <scope>test</scope> <version>1.0.0.RELEASE</version> </dependency>
内容的提问来源于stack exchange,提问作者codependent
相关产品推荐
相关产品推荐

