Hibernate抓取策略以及如何避免cannot simultaneously fetch multiple bags异常

在说解决cannot simultaneously fetch multiple bags异常之前,我先说下抓取策略

注解@Fetch(FetchMode.?)抓取策略有三种

1、FetchMode.JOIN(默认的抓取策略),采用外连接的形式,left outer join ... on

2、FetchMode.SELECT 会另外发送一条sql语句加载当前对象的关联实体

3、FetchMode.SUBSELECT 会另外发送一条select语句抓取前面查询到的所有实体对象的关联实体

通过Hibernate输出的SQL日志看成,个人感觉2、3的差别不是太大 ,都是另起select语句查询与当前某个实体相关联的其他实体。

下面是我写的一个简单DEMO,主要来验证抓取策略和异常的处理方法

表结构

人员表  tb_person

 

+-------------+

| Field       |

+-------------+

| person_id   |

| person_age  |

| person_name |

+-------------+

一个人员可以有多个邮箱,邮箱表,人-邮箱是一对多的关系tb_person_email

 

+-----------+

| Field     |

+-----------+

| id        |

| person_id |

| address   |

+-----------+

事件表,一个人可以有多个事件,一个事件也可有多个人处理,是多对多关系tb_event,tb_person_event

 

+-------------+

| Field       |

+-------------+

| event_id    |

| event_title |

| event_date  |

+-------------+

 

 

+-----------+

| Field     |

+-----------+

| event_id  |

| person_id |

+-----------+

 

要执行的方法是:搜索人,以及相关的事件和邮件。

person.java

第一种写法,采用默认join抓取策略,进行强制抓取person所有关联对象的方式

 

Java代码   收藏代码
  1. @ManyToMany(fetch=FetchType.EAGER)  
  2. @JoinTable(name = "TB_PERSON_EVENT", joinColumns = {@JoinColumn(name = "PERSON_ID")},   
Java代码   收藏代码
  1. inverseJoinColumns = {@JoinColumn(name = "EVENT_ID")})  
  2. public List<Event> getEvents() {  
  3.     return events;  
  4. }  
  5.   
  6.   
  7. @OneToMany(fetch=FetchType.EAGER)  
  8. @JoinTable(name = "TB_PERSON_EMAIL", joinColumns = {@JoinColumn(name = "PERSON_ID")},  
Java代码   收藏代码
  1. inverseJoinColumns = {@JoinColumn(name = "ID")})  
  2. ublic List<Email> getEmails() {  
  3. return emails;  

如果这样写的情况下, 就会报cannot simultaneously fetch multiple bags异常,从SQL日志分析,hibernate是这样执行的

 

Java代码   收藏代码
  1. select *  
  2. from TB_PERSON tp left outer join TB_PERSON_EMAIL tpe1 on tp.person_id = tpe1.person_id   
  3. left outer join TB_PERSON_EMAIL tpe2 on tpe1.id = tpe2.id   
  4. left outer join TB_PERSON_EVENT tpet on tp.person_id = tpet.person_id  
  5. left outer join TB_EVENT te on tpet.event_id = te.event_id  
  6. where tp.person_id = 2;  

 输出的记过,就会出现两个同样的email实体列,所以就报上述异常。

 

如果要避免这个异常,我在网上搜了许多资料都是说把fetch=FetchType.LAZY

变成懒加载模式,或者把List修改成Set集合,这两种我验证过了,是可以行的通的,但是如果不想采取这种两种办法,

怎么办。

 

其实还有一种,是看springside得到的一种方法,代码修改如下

 

Java代码   收藏代码
  1. @ManyToMany(fetch=FetchType.EAGER)  
  2. @JoinTable(name = "TB_PERSON_EVENT", joinColumns = {@JoinColumn(name = "PERSON_ID")},  
Java代码   收藏代码
  1.  inverseJoinColumns = {@JoinColumn(name = "EVENT_ID")})  
  2. @Fetch(FetchMode.SUBSELECT)  
  3. public List<Event> getEvents() {  
  4.     return events;  
  5. }  
  6.   
  7. @OneToMany(fetch=FetchType.EAGER)  
  8. @JoinTable(name = "TB_PERSON_EMAIL", joinColumns = {@JoinColumn(name = "PERSON_ID")},  
Java代码   收藏代码
  1.  inverseJoinColumns = {@JoinColumn(name = "ID")})  
  2. @Fetch(FetchMode.SUBSELECT)  
  3. public List<Email> getEmails() {  
  4.         return emails;  
  5. }  

 这种方法就是在不修改原结构注释的情况下,可以修改一下抓取策略,分开select实体,这样就不会出现重复列现象。

个人感觉还是不错的方法,打算就用它了。

 

另外就是个人并不是太喜欢全抓取,密密麻麻一大堆的SQL打印的控制台上,排查SQL都麻烦,所以最终修改版,个人比较喜欢的注释方法:

 

Java代码   收藏代码
  1. @ManyToMany(fetch=FetchType.LAZY)  
  2. @JoinTable(name = "TB_PERSON_EVENT", joinColumns = {@JoinColumn(name = "PERSON_ID")},  
Java代码   收藏代码
  1.  inverseJoinColumns = {@JoinColumn(name = "EVENT_ID")})  
  2. @Fetch(FetchMode.SUBSELECT)  
  3. public List<Event> getEvents() {  
  4.     return events;  
  5. }  
  6.   
  7. @OneToMany(fetch=FetchType.LAZY)  
  8. @JoinTable(name = "TB_PERSON_EMAIL", joinColumns = {@JoinColumn(name = "PERSON_ID")},  
Java代码   收藏代码
  1.  inverseJoinColumns = {@JoinColumn(name = "ID")})  
  2. @Fetch(FetchMode.SUBSELECT)  
  3. public List<Email> getEmails() {  
  4.         return emails;  
  5. }  

转自:http://dyldragon.iteye.com/blog/788385

### 使用ROS控制六轴机械臂进行物体抓取 #### 一、硬件配置与初始化 为了实现基于ROS的六轴机械臂抓取功能,需先确认所使用的硬件设备及其特性。本案例选用的是xArm 6轴机械臂,其具备较大的工作空间并能响应控制器发出的指令以完成运动规划和末端执行器的操作[^1]。 #### 二、软件架构设计 在ROS框架下,整个系统的软件部分可以分为多个独立的功能模块节点来处理不同的任务需求。例如,在此项目中有两个主要节点被提及:“img_process”负责图像处理分析目标对象位置姿态信息;另一个则是“arm_command”,它接收来自前者的数据并通过算法计算得出适合当前情境下的动作序列发送给实际物理层面中的伺服电机驱动电路板从而带动连杆机构做出相应调整达到预期效果[^2]。 #### 三、具体实施步骤说明如下: ##### 图像预处理阶段 利用摄像头采集场景内的实时画面,并通过OpenCV库函数对这些原始资料做进一步增强对比度亮度调节裁剪等操作以便后续更精确地标定出待拾取物的位置坐标系关系图样特征匹配等工作流程都将在这一环节完成。 ##### 动作规划与仿真验证过程 当获取到准确的目标定位之后,则需要调用MoveIt!插件包来进行路径优化模拟演示查看是否存在碰撞风险或者超出关节角度限制等问题如果一切正常就可以继续向下传递信号准备启动真实世界里的自动化生产线作业模式了当然在此之前还应该反复测试确保万无一失才行哦! 以下是用于启动上述所有进程的一个简单Python脚本示例代码片段: ```python #!/usr/bin/env python import rospy from std_msgs.msg import String def callback(data): rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data) def listener(): # In ROS, nodes are uniquely named. If two nodes with the same # name are launched, the previous one is kicked off. The # anonymous=True flag means that rospy will choose a unique # name for our 'listener' node so that multiple listeners can # run simultaneously. rospy.init_node('listener', anonymous=True) rospy.Subscriber("chatter", String, callback) # spin() simply keeps python from exiting until this node is stopped rospy.spin() if __name__ == '__main__': listener() ``` 该脚本定义了一个订阅者`listener`, 它会监听主题名为 `chatter` 的消息流并将接收到的内容打印出来。这只是一个基础模板,可以根据实际情况修改成适配特定应用场合的形式比如更改话题名称类型参数设置等等细节之处都需要仔细斟酌考量一番才能得到最佳解决方案[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值