Hibernate 配置 双向 对多关联 (未完待续·······)

               从生疏到熟练  是要经历多少遍的练习? 这答案只能向自己找。

以Student和Course为例,一个学生可以选多门课程,一门课程也可以被多个学生选取;

首先  我们创建持久化类Student

 1 package bean;
 2
 3 import java.util.Set;
 4
 5 public class Student {
 6     private long id;
 7     private String name;//学生姓名
 8     private Set<Course> courses;//该学生选择的课程
 9     //省略set、get方法
10 } 

接下来就是持久化类Course

 1 package bean;
 2
 3 import java.util.Set;
 4
 5 public class Course {
 6     private long id;
 7     private String name;//课程名称
 8     private Set<Student> students;//选择该课程的学生
 9         //省略set、get方法
10 }

然后是对象关系映射文件Student.hbm.xml:

 1 <hibernate-mapping>
 2     <class name="bean.Student" table="students">
 3         <id name="id" column="id" type="long">
 4             <generator class="increment"></generator>
 5         </id>
 6         <property name="name" column="name" type="string"></property>
 7         <set name="courses" table="students_courses" cascade="save-update">
 8             <key column="student_id"></key>
 9             <many-to-many class="bean.Course" column="course_id"></many-to-many>
10         </set>
11     </class>
12 </hibernate-mapping>

       多对多关联关系的实现需要一个连接表,<set>的属性指出的就是连接表的名称,<key>指出连接表参照students表id的外键的字段名;<many-to-many>中的class指定与Student多对多关联的类,column指定连接表参照Course映射表(此处由Course.hbm.xml映射为courses表)id的外键的字段名,Course.hbm.xml中的<set>配置与Student.hbm.xml中<set>相反:

Course.hbm.xml:

 1 <hibernate-mapping>
 2     <class name="bean.Course" table="courses">
 3         <id name="id" column="id" type="long">
 4             <generator class="increment"></generator>
 5         </id>
 6         <property name="name" column="name" type="string"></property>
 7         <set name="students" table="students_courses" cascade="save-update" inverse="true">
 8             <key column="course_id"></key>
 9             <many-to-many class="bean.Student" column="student_id"></many-to-many>
10         </set>
11     </class>
12 </hibernate-mapping> 

注意:两个映射文件中设置的连接表的名称以及连接表中的两个字段名需对应相同,如连接表名都为"students_courses"两字段为"student_id"和"course_id",否则会导致不必要的麻烦;连接表的主键为联合主键(student_id,course_id)。

三个表的结构及对应关系如下所示:

接着就是保存对象:

 1 Student s1=new Student();
 2 s1.setName("lisi");
 3 Course c1=new Course();
 4 c1.setName("English");
 5 Course c2=new Course();
 6 c2.setName("science");
 7 s1.setCourses(new HashSet<Course>());
 8 c1.setStudents(new HashSet<Student>());
 9 c2.setStudents(new HashSet<Student>());
10 s1.getCourses().add(c1);
11 s1.getCourses().add(c2);
12 c1.getStudents().add(s1);
13 c2.getStudents().add(s1);
14
15 session.save(c1);
16 session.save(s1);

(1)如果两个映射文件的inverse都设为false(默认),则会出现异常(主键重复)导致插入失败:

org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update

Caused by: java.sql.BatchUpdateException: Duplicate entry ‘1-1‘ for key ‘PRIMARY‘

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:Duplicate entry ‘1-1‘ for key ‘PRIMARY‘

解释:应为两映射文件中的inverse都为true,则Student和Course都去维护关联关系,即同时向连接表中插入记录,则会导致主键重复而插入失败。

解决办法:

     ——将其中一方的inverse设为true,让对方维持关联关系;

     ——将s1.getCourses().add(c1);或 c1.getStudents().add(s1);删除,因为若某个Course中的students集合为空时,它就不会去向连接表中添加记录,也就不会与Student向连接表中插入记录时冲突而主键重复。

(2)如果都设为true,则都不会向连接表中插入记录而只是向两表中插入记录(两者都认为对方会维持关联关系)执行的SQl语句为:

1 Hibernate: insert into courses (name, id) values (?, ?)
2 Hibernate: insert into students (name, id) values (?, ?)
3 Hibernate: insert into courses (name, id) values (?, ?) 

(3)设一方的inverse为true,正常插入数据时输出的SQL语句为:

1 Hibernate: insert into courses (name, id) values (?, ?)
2 Hibernate: insert into students (name, id) values (?, ?)
3 Hibernate: insert into courses (name, id) values (?, ?)
4 Hibernate: insert into students_courses (student_id, course_id) values (?, ?)
5 Hibernate: insert into students_courses (student_id, course_id) values (?, ?)  

删除学生(Student)记录:

1 Student s=(Student)session.get(Student.class, 2L);
2 session.delete(s);

注意:

    (1)如果不是Student维持关联关系:

           ——若连接表students_courses中有参照students表中该记录的记录(即在students_courses表中存在student_id为2L的记录)时,则删除失败。

           ——若连接表students_courses中没有参照students表中该记录的记录时,则可以成功地将该记录删除。

     (2)如果是Student维持关联关系:

           ——先将连接表students_courses中参照students表中该记录的记录删除,然后将该学生记录从students表中删除

查询某学生选的所有课程:

1 Student s=(Student)session.get(Student.class, 2L);
2           Set<Course> set=s.getCourses();
3
4           for (Iterator iterator = set.iterator(); iterator.hasNext();) {
5 Course course = (Course) iterator.next();
6 System.out.println(course.getName());  

某学生又选了一门新课(增加了连接表中的一条记录):

1 Student s=(Student)session.get(Student.class, 2L);
2 Course c=(Course)session.get(Course.class,1L );
3 s.getCourses().add(c);
4 c.getStudents().add(s);

删除某学生的一条选课记录(删除了连接表中的一条记录):

1  Student s=(Student)session.get(Student.class, 2L);
2 Course c=(Course)session.get(Course.class,1L );
3 s.getCourses().remove(c);  

(此时只会删除连接表中的一条记录而不会去修改Students和courses表中的记录)

注意:双向多对多,还可以拆成两个多对一
1  <many-to-one name="stu" class="Student">
2           <column name="stuId"></column>
3         </many-to-one>
4         <many-to-one name="cou" class="Course">
5           <column name="couid"></column>
6         </many-to-one>
 

当遇到困难、 问题其实是好的, 只在懂不懂得努力去解决。

欢迎、感谢 您来指点我:http://www.cnblogs.com/smbk/

时间: 2024-10-23 21:24:42

Hibernate 配置 双向 对多关联 (未完待续·······)的相关文章

听风讲MVC丶 —— 一言不合就撸码 (未完待续&#183;&#183;&#183;&#183;&#183;&#183;)

     希望你看了此小随 可以实现自己的MVC框架     也祝所有的程序员身体健康一切安好                                                                                                                                                ——久伴深海丶默 1.什么是前端控制器(font controller).Java Web中的前端控制器是应用的门面,

Exp2 后门原理与实践(未完待续)

Exp2 后门原理与实践 实验环境 攻击机 kali 4.14(64位) (IP: 10.0.2.6/24) 靶机 ubuntu 16.04(32位) (IP: 10.0.2.4/24) windows 7 sp1(64位) (IP: 10.0.2.7/24) nc/ncat的使用 nc(全称是netcat)是一个用于TCP/UDP连接和监听的linux工具,有着网络工具中的"瑞士军刀"的美誉.nc的实现版本大致有两种,一种是带有-e或-c 选项可以直接给出执行命令,另一种不支持-e选

[译]App Framework 2.1 (1)之 Quickstart (未完待续)

最近有移动App项目,选择了 Hybrid 的框架Cordova  和  App Framework 框架开发. 本来应该从配置循序渐进开始写的,但由于上班时间太忙,这段时间抽不出空来,只能根据心情和兴趣,想到哪写到哪,前面的部分以后慢慢补上. App Framework 前生是是叫 jqMobi 注意大家不要和 jQuery Mobile 混淆了,它们是两个不同的框架,一开始我还真混淆了0.01秒. 这里我先翻译一下Quickstart 部分,一是自己工作上用的上,二是也想顺便练练英文,最关键

git个人使用总结 —— idea命令行、撤销commit (未完待续)

近期在使用git,最开始在idea界面操作,后来要求用命令行.刚开始还不是很习惯,感觉很麻烦,用了几天后感觉爽极了! 其实git的命令也不是很多,熟悉一段时间就差不多能顺利使用了.使用过程中遇到了各种各样的问题,有些小问题就在这里集中总结一下. 1.idea命令行.git安装后就自带终端git bash,使用起来很方便.但是用idea开发,开发后还要在相应文件夹下打开git bash很麻烦.其实idea也带有终端terminal,在最下方可以找到,在这里就可以执行命令.但是如果是默认方式安装的g

React v16-alpha 源码简读【未完待续】

一.物料准备 1.克隆react源码, github 地址:https://github.com/facebook/react.git 2.安装gulp 3.在react源码根目录下: $npm install $gulp default (建议使用node 6.0+) gulp将文件处理在根目录下的build文件夹中,打开build查看react的源码,结构清晰,引用路径明了 二.从生成 virtual dom 开始 react 生成一个组件有多种写法: es 5下:var Cp=React.

jdbc14 及 jdbc16 共存所带来的问题【未完待续】

在JAVA中JDK版本与JDBC版本的一致性十分重要,开发都们常常会忽略了这一点导致很多不必要的错误.昨天给客户排查了一个关于EDB在JBoss中使用时关于这方面的问题,希望给大家一点启发. 系统环境: Red Hat Enterpirse Linux 6 JBoss Enterprise Application Server 6 EnterpriseDB Postgres Plus Advanced Server 9 Oracle JDK 1.6 问题症状: 在JBoss日志中间歇性地出现以下

AutoMapper介绍(未完待续、部分没实现)

实体间转换工具.其实也可以用Json来实现同名属性.异名属性(用JsonProperty指明)的自动转换 最新版本6.11 需要使用vs2013以上.vs2012下载新版 nuget会遇到问题.只能旧版. 1 using AutoMapper; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Web; 6 using System.Web.Mvc; 7 8 namesp

JavaWeb ajax编程(未完待续)

1.Ajax 1.1Ajax的定义 Ajax:(Asynchronous JavaScript And XML)指异步 JavaScript 及 XML. 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的 Web 应用程序的技术,是基于JavaScript.XML.HTML.CSS新用法. Ajax:只刷新局部页面的技术 JavaScript:更新局部的网页 XML:一般用于请求数据和响应数据的封装 XMLHttpRequest对象:发送请求到服务器并获得返回结果 CSS:美化页面

性能测试调优篇---未完待续

性能测试调优一:1.首先,看下选测交易的整个走向纯系统内部交易:选测交易如果是系统内的交易,每一步请求都和系统交互几次,访问了几个数据库,访问了数据库的那几张表??该交易走了那几台机器,这几台机器的网络连接情况是什么样的??这几台机器是通过走的是哪些虚拟网卡,走了哪些路由器??带宽是什么情况??该交易在这几台机器上消耗了多少CPU,内存,及其对磁盘做了多少次的访问??从方法层面,从该交易的发起到结束,起了多少线程,调用了哪些相关的方法以及接口,访问了哪些表???跨系统交易:该交易发起后,每一步请