cannot simultaneously fetch multiple bags异常的解决

本文探讨了EJB持久层中出现的cannotsimultaneously fetchmultiplebags异常,并提供了解决方案。异常由实时加载过多异同对象导致,通过使用Set容器而非List容器来存放多方数据可以避免此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文来自于http://howsun.blog.sohu.com/119020926.html

EJB持久层cannot simultaneously fetch multiple bags异常的解决

    病理特征:Caused by: org.hibernate.HibernateException: cannot simultaneously fetch multiple bags,

    堆栈信息:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'initSystemDataBySpringListeren': Injection of resource fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'service': Injection of resource fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'assistantDao': Injection of resource fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [spring-core-config.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: cannot simultaneously fetch multiple bags

     ......

     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容器内的对象的类中是不是还有类似问 题。

### 关于 ARM Cortex-A PC 异常移动程序的示例 在 ARM 架构中,Program Counter (PC) 是一个特殊的寄存器,用于指向当前执行指令的地址。当发生异常时,ARM 处理器会自动调整 PC 的值以跳转到相应的异常向量表条目。这种行为称为“异常移动”。以下是有关 ARM Cortex-A 系列处理器中 PC 异常移动的相关信息及其示例。 --- #### 1. **异常机制简介** 在 ARM Cortex-A 系列中,异常是一种中断正常程序流的行为。每当检测到特定事件(如外部中断、系统调用或内存访问错误),CPU 就会暂停当前任务并切换至预定义的异常处理程序[^1]。在此过程中,PC 的值会被更新为对应异常类型的入口地址。 --- #### 2. **异常向量表结构** 异常向量表是一个固定大小的数组,其中每项都指向某个具体的异常处理函数。传统 ARM 架构下,默认基址位于地址 `0x0`;然而,在某些现代 SoC 设计里也可以重新定位该表格位置。对于 ARMv7 及更高版本而言,异常向量偏移如下所示: | **异常类型** | **偏移量** | **描述** | |----------------------|--------------|-------------------------------------------------------------------------------------------| | Reset | 0x00 | 初始化 CPU 后首次启动所使用的初始代码段 | | Undefined Instruction| 0x04 | 执行了一条未定义或者保留给未来扩展用途的指令 | | Software Interrupt(SWI)| 0x08 | 用户模式下的特权操作请求 | | Prefetch Abort | 0x0C | 尝试从无效/不可访问区域提取指令 | | Data Abort | 0x10 | 访问非法数据地址 | | IRQ | 0x18 | 外部设备发出的标准级别中断信号 | | FIQ | 0x1C | 更高优先级快速中断 | 一旦触发某类异常,PC 即刻被设定成上述列表里的相应数值加上基础矢量起点形成最终目标地址[^2]。 --- #### 3. **PC 移动的具体实现方式** 下面给出了一个简单的汇编语言例子演示如何编写基本的 SWI(Software Interrupt)服务例程以及关联的返回逻辑: ```asm /* Exception Handler Example */ .global _start _start: /* Main Program Entry Point */ swi_handler: STMFD sp!, {lr} @ Save Link Register onto Stack Frame @ lr contains the address to return after exception handling completes process_swi_request: MOV r0, #1 @ Simulate processing an SWI request by setting R0=1 as result value. prepare_to_return_from_exception: LDMFD sp!, {pc}^ @ Restore original LR into PC and switch back mode bits simultaneously. main_program_code: SVC #0 @ Trigger a software interrupt which causes control flow jump to swi_handler above. @ After execution finishes there, it will resume here with updated registers states including new values stored inside general purpose ones like R0 etc.. ``` 在这个案例中: - 使用了 `SVC` 指令模拟产生软中断。 - 当前线程的状态信息连同链接寄存器一起压入堆栈保存下来以防丢失。 - 在完成必要的计算之后再把先前暂存的内容弹出来恢复原状从而继续往下走原来被打断的地方[^3]。 --- #### 4. **注意事项** 虽然上面的例子展示了最基本的原理,但在实际应用开发当中还需要考虑更多因素,例如多层嵌套异常的支持、上下文中断屏蔽状态管理等问题。此外不同厂商生产的基于相同核心规格的产品之间可能存在细微差异因此务必查阅官方文档确认细节部分。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值