迁移至Hibernate 6:ArrayList数据持久化及旧数据兼容咨询
问题与解决方案
原问题背景
实体类定义:
import java.io.Serializable; import java.time.ZonedDateTime; import java.util.ArrayList; @Getter @Setter @Entity(name = "trackgeodata") @Table(name = "trackgeodata") public class TrackGeodata implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Lob @Column(name = "times") private ArrayList<ZonedDateTime[]> times; @Lob @Column(name = "altitudes") private ArrayList<int[]> altitudes; }
此前通过@Lob注解存储嵌套集合类型数据运行正常,迁移至Spring Boot 3.2 + Hibernate 6时出现错误:
class org.hibernate.type.internal.BasicTypeImpl cannot be cast to class org.hibernate.type.BasicPluralType (org.hibernate.type.internal.BasicTypeImpl and org.hibernate.type.BasicPluralType are in unnamed module of loader 'app')
1. Hibernate 6持久化嵌套ArrayList的正确方式
Hibernate 6对类型映射的校验更严格,不再支持直接用@Lob隐式序列化嵌套集合,推荐两种方案:
方案一:JSON格式存储(推荐)
将嵌套集合序列化为JSON存储,可读性强且支持数据库原生JSON查询,适配主流数据库的JSON类型:
import org.hibernate.type.SqlTypes; // ... 其他导入 @Getter @Setter @Entity(name = "trackgeodata") @Table(name = "trackgeodata") public class TrackGeodata implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; // PostgreSQL用jsonb,MySQL用json,根据使用的数据库调整columnDefinition @Column(name = "times", columnDefinition = "jsonb") @JdbcTypeCode(SqlTypes.JSON) private ArrayList<ZonedDateTime[]> times; @Column(name = "altitudes", columnDefinition = "jsonb") @JdbcTypeCode(SqlTypes.JSON) private ArrayList<int[]> altitudes; }
Hibernate会自动完成集合与JSON的序列化/反序列化,无需额外处理。
方案二:二进制序列化存储(延续旧逻辑)
如果要坚持用二进制LOB存储,需要显式指定序列化类型:
import org.hibernate.annotations.Type; import org.hibernate.type.SerializableType; // ... 其他导入 // ... 类定义省略 @Lob @Type(SerializableType.class) @Column(name = "times") private ArrayList<ZonedDateTime[]> times; @Lob @Type(SerializableType.class) @Column(name = "altitudes") private ArrayList<int[]> altitudes;
这种方式延续旧的Java序列化逻辑,但二进制数据可读性差,不利于后续查询和维护。
2. 兼容旧数据的迁移方案
旧数据是通过Java序列化存储的二进制LOB,需根据选择的新存储方式处理:
若选择JSON存储方案
- 新增JSON字段:修改数据库表,新增两个JSON类型字段(比如
times_json、altitudes_json),保留原有的times、altitudes二进制字段。 - 批量迁移数据:编写迁移脚本或Spring Boot批量处理代码,遍历所有
trackgeodata记录:- 读取原二进制字段的数据,反序列化为对应的集合对象。
- 将集合序列化为JSON字符串,写入新增的JSON字段。
- 切换实体映射:修改实体类,将字段映射到新增的JSON字段,删除原
@Lob相关配置。 - 清理旧字段:确认数据迁移完成且系统稳定运行后,删除原二进制LOB字段。
若选择二进制序列化方案
直接修改实体类添加@Type(SerializableType.class)即可,无需数据迁移,旧数据可直接读取。
内容的提问来源于stack exchange,提问作者Folli
相关产品推荐
相关产品推荐

