升级H2至2.1.212/2.1.214后CAST AS TEXT报精度超限错误
H2升级2.x版本后CAST转TEXT类型报精度越界错误
问题表现
将H2数据库从Spring Boot默认提供的1.4.200版本升级至2.1.212、2.1.214版本后,执行包含CAST转换为TEXT类型的查询时抛出如下异常:
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Precision ("2147483647") must be between "1" and "1000000000" inclusive; SQL statement: select distinct userpermis0_.user_id as col_0_0_ from markings.user_permissions_map userpermis0_ inner join markings.marking marking1_ on (marking1_.name=userpermis0_.marking_name and marking1_.unique_name=REGEXP_REPLACE(lower(?),'[^a-z0-9]+','-','g')) where (cast(? as varchar(2147483647)) is null or userpermis0_.user_id>?) and (cast(? as varchar(2147483647)) is null or lower(userpermis0_.user_id) like ?) order by userpermis0_.user_id asc limit ? [90150-214] at org.h2.message.DbException.getJdbcSQLException(DbException.java:632) ~[h2-2.1.214.jar:2.1.214] at org.h2.message.DbException.getJdbcSQLException(DbException.java:477) ~[h2-2.1.214.jar:2.1.214] at org.h2.message.DbException.get(DbException.java:223) ~[h2-2.1.214.jar:2.1.214] at org.h2.command.Parser.getInvalidPrecisionException(Parser.java:6325) ~[h2-2.1.214.jar:2.1.214] at org.h2.command.Parser.readIfDataType1(Parser.java:6285) ~[h2-2.1.214.jar:2.1.214] at org.h2.command.Parser.readIfDataType(Parser.java:6087) ~[h2-2.1.214.jar:2.1.214]
业务层使用JPA编写的查询逻辑如下:
@Query("SELECT DISTINCT u.username" + " FROM UserPermissionsMap u" + " INNER JOIN Marking m ON m.name = u.markingName AND m.uniqueName = REGEXP_REPLACE(lower(:name), '[^a-z0-9]+', '-', 'g') " + " WHERE ( cast(:lastUsernameReturned as text) IS NULL OR u.username > :lastUsernameReturned )" + " AND ( cast(:usernameContains as text) IS NULL OR lower(u.username) LIKE %:usernameContains% )")
对应Maven POM中的H2依赖配置:
... <h2.version>2.1.214</h2.version> </properties> ... <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>${h2.version}</version> <!-- 原v1.4.200版本由org.springframework.boot:spring-boot-dependencies:2.5.6默认提供 --> </dependency>
根因分析
报错核心逻辑:
Hibernate在解析JPQL中的cast(xxx as text)语法时,会自动将TEXT类型映射为varchar(2147483647)(即Integer.MAX_VALUE长度的可变字符串);而H2 2.x版本新增了VARCHAR类型精度校验,要求精度值必须在1到1000000000区间内,2147483647超出了该上限,因此直接抛出SQL语法异常。
修复方案
可根据实际项目情况选择以下任意一种方案修复:
- 调整JPQL中的CAST语法:不使用
as text,改为指定符合业务长度的VARCHAR精度,例如将cast(:lastUsernameReturned as text)修改为cast(:lastUsernameReturned as varchar(255)),精度值匹配实际username字段的长度即可,避免Hibernate自动生成超大精度的类型定义。 - 升级Spring Boot版本:将Spring Boot升级到2.7.x及以上版本,该版本之后官方已经适配了H2 2.x的Hibernate方言,修复了TEXT类型映射时生成非法varchar精度的问题。
- 自定义H2方言类型映射:如果暂时无法升级Spring Boot版本,也可以自定义H2的Hibernate方言类,重写TEXT类型的映射规则,将最大长度限制在H2允许的1000000000以内。
内容的提问来源于stack exchange,提问作者ScrappyDev
相关产品推荐
相关产品推荐

