Spring Boot 2.7.1升级后DataJpaTest中NUMERIC默认精度异常问题
Spring Boot 2.7.1升级后H2模拟PostgreSQL时NUMERIC数据截断问题
问题场景
使用@DataJpaTest,通过schema.sql和data.sql搭建基于H2模拟PostgreSQL的测试环境。将spring-boot-starter-parent从2.6.3升级到2.7.1后,测试出现断言失败:
org.opentest4j.AssertionFailedError: Expected :1.4321 Actual :1
查看H2数据库发现,problematic_number字段存储的值为1而非插入的1.4321,升级前测试完全正常。将schema.sql中字段定义改为NUMERIC(10,4)后测试恢复正常。
相关代码
schema.sql:
CREATE TABLE IF NOT EXISTS some_table( id BIGSERIAL, name TEXT, problematic_number NUMERIC NOT NULL );
data.sql:
INSERT INTO some_table (name, problematic_number) VALUES ('something', 1.4321);
原因分析
核心原因是Spring Boot 2.7.x升级了依赖的H2数据库版本(从2.0.x系列升级到2.1.x+),H2在PostgreSQL兼容模式下对无参数NUMERIC类型的默认处理逻辑发生了变更:
- Spring Boot 2.6.x配套的H2版本中,无参数
NUMERIC默认会保留输入的小数部分,行为接近PostgreSQL原生(PostgreSQL中NUMERIC默认精度无限制,会保留输入的所有小数位)。 - 升级后的H2版本在PostgreSQL模式下,将无参数
NUMERIC默认映射为NUMERIC(18,0),即默认小数位为0,导致插入的小数被直接截断为整数。
解决方案
有两种可行的处理方式:
1. 显式指定NUMERIC的精度和小数位
直接在表结构定义中明确NUMERIC的精度和小数位,确保行为一致:
CREATE TABLE IF NOT EXISTS some_table( id BIGSERIAL, name TEXT, problematic_number NUMERIC(10,4) NOT NULL );
这种方式最直接,也能避免依赖数据库的默认行为,保证表结构定义的明确性。
2. 调整H2配置参数
在测试环境的H2连接URL中指定默认的NUMERIC精度和小数位,比如在application-test.properties中配置:
spring.datasource.url=jdbc:h2:mem:testdb;MODE=PostgreSQL;DEFAULT_NUMERIC_PRECISION=10;DEFAULT_NUMERIC_SCALE=4;DB_CLOSE_DELAY=-1
通过DEFAULT_NUMERIC_PRECISION和DEFAULT_NUMERIC_SCALE参数,强制H2在PostgreSQL模式下使用自定义的默认精度,匹配升级前的行为。
内容的提问来源于stack exchange,提问作者Sebastian
相关产品推荐
相关产品推荐

