云自无心水自闲

天平山上白云泉,云自无心水自闲。何必奔冲山下去,更添波浪向人间!
posts - 288, comments - 524, trackbacks - 0, articles - 6
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
我使用的是annotation方式的hibernate配置。结果在启动Tomcat的时候报错:
Invocation of init method failed; nested exception is org.hibernate.HibernateException: cannot simultaneously fetch multiple bags
解决方法:
去除Annotation中的所有FetchType="EAGAR"




评论

# re: Hibernate启动报错cannot simultaneously fetch multiple bags  回复  更多评论   

2013-05-22 10:09 by 黄威
cannot simultaneously fetch multiple bags异常是由于持久层实时加载太多异同对象而致。例如用户登录时,同步实时加载用户的角色对象、权限对象,而往往这些关系都是多对多关系,就单一列内容来看存在重复的值,从而引起multiple bags。我在网上搜索这类结果,几乎都提出一个解决办法——采用延迟加载,即fetch=FetchType.LAZY,这样就束缚了框架的强大功能,也有提过用@IndexColumn解决,但@IndexColumn是Hibernate的东西,不是JPA规范(下文有讨论)。既要实时加载,又保证不会出现主题问题,这就是本文所要探讨的。

JPA规范中,一对多或多对多的多方数据抓取过来后必须用容器类存,例如Set、List、Map等,初学者可能没有对这个几个容器认真研究,随便拿一个就用。事实上这几个容器有很大的区别,本文不具体讨论这些容器的区别和功能,但提一个特别要注意的区别——导致本文主题的产生——就是容器内是否允许重复值,那让们简单地了解下这此容器的特性:

Set:

_Set中不允许存放重复元素;
_Set中的元素是无序的。

List:

_List中可以存放重复元素;
_List中的元素是一个有序的集合,可以通过访问List中的元素。

Map:

_Map是以键/值存放数据,因此它有较高的存取性能;
_Map中不允许重复的键,但可以有重复的值

有了这些区别,我们就可以开始寻找主题问题,当持久框架抓取一方的对象时,同时加载多方的对象放进容器中,多方又可能与关联其它对象,Hibernate实现的JPA,默认最高抓取深度含本身级为四级(它有个属性配置是0-3),若多方(第二级)存在重复值,则第三级中抓取的值就无法映射,按照这个道理,就应该报出无法同时加载多个包之异常。由于国内EJB3.0以后的教材是少而甚少,更没有较完善的JPA手册,所以笔者这样的理解可能会引起质疑,但事实上,笔者是通过这个思路解决了问题:

即@ManyToMany或@OneToMany的Many方此时一定用Set容器来存放,而不能用List集合。

不过Hibernate有些功能超越了JPA规范,它支持真正的List集合,映射集合的方式和以前完全一样,只不过要新增 @IndexColumn注解,该注解允许你指明存放索引值的字段。但实际上是创建唯一性索引,抓取多方的结果也是唯一的,就是上述Set容器不允许重复元素的道理一样。

出现此异常的读者,先看看自己是不是用了List集合而导致此问题的发生,若是用Set还出现此问题,则去看Set容器内的对象的类中是不是还有类似问题。

# re: Hibernate启动报错cannot simultaneously fetch multiple bags  回复  更多评论   

2013-06-23 13:05 by usherlight
@黄威

谢谢你详尽的解释

只有注册用户登录后才能发表评论。


网站导航: