Java Spring多对多关联报错:Hibernate PersistentSet数组越界异常
Spring多对多关联查询抛出ArrayIndexOutOfBoundsException问题解决
问题现象
在Java Spring应用中通过中间实体AssignedItemUser配置多对多关联时,Item侧调用item.getAssignedItemUsers().size()能正常返回结果(例如101),但User侧调用user.getAssignedItemUsers().size()时抛出ArrayIndexOutOfBoundsException,错误信息为:Index 3 out of bounds for length 3。
相关实体代码
User实体
@Entity @Table(name = "users") public class User { @Id @GeneratedValue private Long id; ... @OneToMany(mappedBy = "user") private Set<AssignedItemUser> assignedItemUsers = new HashSet<AssignedItemUser>(); ... }
Item实体
@Entity @Table(name = "items", uniqueConstraints = { @UniqueConstraint(columnNames = { "slug" })}) public class Item { @Id @GeneratedValue private long id; ... @OneToMany(mappedBy = "item") private Set<AssignedItemUser> assignedItemUsers = new HashSet<AssignedItemUser>(); ... }
关联实体AssignedItemUser
@Entity @Table(name = "new_assigned_item_users") public class AssignedItemUser { @Id private BigInteger id; @ManyToOne @JoinColumn(name = "user_id") User user; @ManyToOne @JoinColumn(name = "item_id") Item item; }
排查与根因分析
打印异常栈追踪后发现,异常来源于EnumJavaType相关方法。进一步检查发现:User和Item实体都包含枚举字段,而中间实体AssignedItemUser没有枚举字段。
问题根源在于:Hibernate默认使用ORDINAL方式映射枚举类型,即把枚举的索引值(从0开始连续递增)存储到数据库。但实际数据库中,枚举对应的整数值不连续(例如存在0、2、3这样的值),当Hibernate尝试用ordinal索引去匹配数据库中的非连续数值时,就会触发数组越界异常。
解决方案
为实体中的枚举字段添加自定义转换器,明确指定枚举与数据库值的映射逻辑,替代默认的ORDINAL映射:
- 实现
AttributeConverter接口,定义枚举和数据库值的转换规则:
@Converter(autoApply = true) public class YourEnumConverter implements AttributeConverter<YourEnum, Integer> { @Override public Integer convertToDatabaseColumn(YourEnum attribute) { if (attribute == null) { return null; } return attribute.getDbValue(); // 假设枚举类有获取对应数据库值的方法 } @Override public YourEnum convertToEntityAttribute(Integer dbData) { if (dbData == null) { return null; } return Arrays.stream(YourEnum.values()) .filter(e -> e.getDbValue().equals(dbData)) .findFirst() .orElseThrow(() -> new IllegalArgumentException("Invalid enum value: " + dbData)); } }
- 若未设置
autoApply = true,则在实体的枚举字段上添加@Convert注解:
@Column(name = "your_enum_column") @Convert(converter = YourEnumConverter.class) private YourEnum yourEnum;
通过自定义转换器,让Hibernate按照枚举对应的实际数据库值进行映射,避免因ordinal索引不匹配导致的数组越界问题。
内容的提问来源于stack exchange,提问作者adkra
相关产品推荐
相关产品推荐

