JPA多对多关联添加数据时抛出StackOverflowError问题求助
解决JPA多对多关联插入时的StackOverflowError问题
兄弟,你猜的完全没错!这种插入第二个元素就爆StackOverflowError的情况,十有八九是双向多对多关联导致的循环引用,最常见的坑就是实体类的toString()、equals()或者hashCode()方法里互相调用了对方的集合属性,直接搞出无限递归了。
先揪出问题根源
你先去检查下你的两个关联实体(比如MaterialServer和Material):
- 是不是
MaterialServer的toString()里打印了materials集合? - 同时
Material的toString()里又输出了对应的materialServers集合? - 或者
equals()/hashCode()方法里用到了对方的集合属性?
这种情况下,不管是你自己打印日志,还是JPA框架在处理对象时序列化,都会陷入“A调用B的toString → B又调用A的toString”的死循环,最后栈直接炸了。
给你几个具体的解决办法
1. 修正toString/equals/hashCode方法
这是最常见的修复点:
- toString():只打印实体自己的属性,别碰关联的集合。比如
MaterialServer的toString只输出id、name这些自身字段,把materials从toString里删掉;Material那边同理,去掉materialServers。
举个例子(MaterialServer的toString):@Override public String toString() { return "MaterialServer{" + "id=" + id + ", name='" + name + '\'' + '}'; // 千万别加", materials=" + materials这行! } - equals()和hashCode():只拿实体的主键(比如
id)来实现,别依赖关联的集合。一来集合在对象没持久化时可能是null,二来很容易引入循环引用。
示例代码:@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MaterialServer that = (MaterialServer) o; return Objects.equals(id, that.id); } @Override public int hashCode() { return Objects.hash(id); }
2. 把双向关联的配置搞正确
你贴的是MaterialServer的关联配置,得确认Material类里的反向关联是不是加了mappedBy:
- 反向关联一定要用
mappedBy指定由MaterialServer来维护中间表,别让两边都去操作中间表,不然不仅容易出循环,还可能搞出重复数据。
比如Material类里的反向关联应该是这样:
划重点:只有拥有方(这里是MaterialServer)需要配置@JoinTable,反方只用mappedBy指向拥有方的关联属性就行。@ManyToMany(mappedBy = "materials", fetch = FetchType.LAZY) private Collection<MaterialServer> materialServers;
3. 插入数据时别瞎操作
插入双向多对多的数据,只需要维护拥有方的集合就行,不用管反方的,JPA会自动处理中间表:
// 创建对象 MaterialServer server = new MaterialServer(); Material material1 = new Material(); Material material2 = new Material(); // 只给拥有方的集合加元素 server.getMaterials().add(material1); server.getMaterials().add(material2); // 直接持久化拥有方,中间表数据JPA会自动插 entityManager.persist(server);
最后总结一下
StackOverflowError在JPA多对多里基本都是循环递归搞的,先查toString/equals/hashCode这几个方法,再确认双向关联的配置,最后按规范插入数据,应该就能解决问题了。
内容的提问来源于stack exchange,提问作者user2147674
相关产品推荐
相关产品推荐

