Hibernate 6一次性抓取过多数据触发SQL Server行大小超限异常
Hibernate 6升级后SQL Server行大小超限问题解决方案
问题场景
有包含大量字段和自引用的大型实体(示例代码如下),升级到Hibernate 6后,所有字段及@ManyToOne关联被默认join fetch,导致SQL Server抛出行大小9020超过允许的最大行大小8060的异常:
@Entity public class Person{ private String firstName; private String lastName; private String title; .... 50 more columns .... @ManyToOne @JoinColumns({ @JoinColumn(name = "k1", referencedColumnName = "k1"), @JoinColumn(name = "k2", referencedColumnName = "k2") }) private Person representation; } @Entity public class Assignment{ @ManyToOne @JoinColumn(...) private Person leader; @ManyToOne @JoinColumn(...) private Person employee; }
异常核心提示:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Eine Zeile der Größe 9020 kann nicht erstellt werden, da sie länger als die zulässige maximale Zeilengröße von 8060 wäre.
解决方案
1. 调整单个关联的抓取策略
给@ManyToOne显式设置延迟加载,或者指定抓取模式为SELECT,避免默认的join fetch:
// 方式1:设置延迟加载,按需加载关联对象 @ManyToOne(fetch = FetchType.LAZY) @JoinColumns({ @JoinColumn(name = "k1", referencedColumnName = "k1"), @JoinColumn(name = "k2", referencedColumnName = "k2") }) private Person representation; // 方式2:保持立即加载但用SELECT模式(不生成join语句) @ManyToOne(fetch = FetchType.EAGER) @Fetch(FetchMode.SELECT) @JoinColumns({...}) private Person representation;
2. 全局修改Hibernate默认抓取行为
在配置文件中添加参数,禁用EAGER关联的默认join fetch,让Hibernate改用单独查询的方式加载关联:
# application.properties中配置 hibernate.jpa.compliance.fetch_eager_join=false
或在persistence.xml中配置:
<property name="hibernate.jpa.compliance.fetch_eager_join" value="false"/>
3. 拆分大型实体
把Person中过多的字段拆分成独立子实体,用@OneToOne延迟加载关联,减少单表的行内数据体积:
@Entity public class Person{ private String firstName; private String lastName; private String title; @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) private PersonExtraDetails extraDetails; @ManyToOne(fetch = FetchType.LAZY) @JoinColumns({...}) private Person representation; } @Entity public class PersonExtraDetails{ // 原来的50+个额外字段 }
4. 优化SQL Server表结构
如果数据库层面允许,调整表的存储选项,把大字段移到行外存储:
-- 启用大值类型行外存储 EXEC sp_tableoption 'Person', 'large value types out of row', 1;
对于SQL Server 2016及以上版本,还可以启用页压缩进一步减少行大小:
ALTER TABLE Person SET (DATA_COMPRESSION = PAGE);
内容的提问来源于stack exchange,提问作者Mr.H.
相关产品推荐
相关产品推荐

