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

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

首先  我们创建持久化类Student

 package bean;  

 import java.util.Set;  

 public class Student {
private long id;
private String name;//学生姓名
private Set<Course> courses;//该学生选择的课程
//省略set、get方法
}

接下来就是持久化类Course

 package bean;  

 import java.util.Set;  

 public class Course {
private long id;
private String name;//课程名称
private Set<Student> students;//选择该课程的学生
//省略set、get方法
}

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

 <hibernate-mapping>
<class name="bean.Student" table="students">
<id name="id" column="id" type="long">
<generator class="increment"></generator>
</id>
<property name="name" column="name" type="string"></property>
<set name="courses" table="students_courses" cascade="save-update">
<key column="student_id"></key>
<many-to-many class="bean.Course" column="course_id"></many-to-many>
</set>
</class>
</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:

 <hibernate-mapping>
<class name="bean.Course" table="courses">
<id name="id" column="id" type="long">
<generator class="increment"></generator>
</id>
<property name="name" column="name" type="string"></property>
<set name="students" table="students_courses" cascade="save-update" inverse="true">
<key column="course_id"></key>
<many-to-many class="bean.Student" column="student_id"></many-to-many>
</set>
</class>
</hibernate-mapping>

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

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

接着就是保存对象:

 Student s1=new Student();
s1.setName("lisi");
Course c1=new Course();
c1.setName("English");
Course c2=new Course();
c2.setName("science");
s1.setCourses(new HashSet<Course>());
c1.setStudents(new HashSet<Student>());
c2.setStudents(new HashSet<Student>());
s1.getCourses().add(c1);
s1.getCourses().add(c2);
c1.getStudents().add(s1);
c2.getStudents().add(s1); session.save(c1);
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语句为:

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

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

 Hibernate: insert into courses (name, id) values (?, ?)
Hibernate: insert into students (name, id) values (?, ?)
Hibernate: insert into courses (name, id) values (?, ?)
Hibernate: insert into students_courses (student_id, course_id) values (?, ?)
Hibernate: insert into students_courses (student_id, course_id) values (?, ?)

删除学生(Student)记录:

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

注意:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. Hibernate 配置双向多对多关联

    本文解决问题:Hibernate 中配置项目(Project) 员工(Employee)   双向多对多关联 方案一:直接配置双向多对多 方案二:配置第三个关联类(xml)   将多对多查分开来(形成 ...

  2. Hibernate二级缓存(未完待续)

    1.Hibernate的cache介绍: Hibernate实现了良好的Cache机制,可以借助Hibernate内部的Cache迅速提高系统的数据读取性能.Hibernate中的Cache可分为两层 ...

  3. php-安装与配置-未完待续2

    一,准备工作 在入门指引中,我们已经知道PHP的3个应用领域,不同的场景,需要安装的东西是不同的.具体如下: 服务器端脚本,在通常情况下,需要三样东西:PHP 自身.一个 web 服务器和一个 web ...

  4. Go web编程学习笔记——未完待续

    1. 1).GOPATH设置 先设置自己的GOPATH,可以在本机中运行$PATH进行查看: userdeMacBook-Pro:~ user$ $GOPATH -bash: /Users/user/ ...

  5. MVC丶 (未完待续······)

         希望你看了此小随 可以实现自己的MVC框架     也祝所有的程序员身体健康一切安好                                                     ...

  6. [python]爬代理ip v2.0(未完待续)

    爬代理ip 所有的代码都放到了我的github上面, HTTP代理常识 HTTP代理按匿名度可分为透明代理.匿名代理和高度匿名代理. 特别感谢:勤奋的小孩 在评论中指出我文章中的错误. REMOTE_ ...

  7. 阿里云服务器:IIS网站的架设(一、环境设置与安装IIS网站 二、网站的基本设置 三、建立新网站(未完待续))

    Windows Server 2012 R2的Internet Information Services (IIS)网站的模块化设计,可以减少被攻击面并减轻管理负担,让系统管理员更容易架设安全的具备高 ...

  8. odoo11 model+Recordset 基础未完待续

    Model 一个模型代表了一个业务对象 本质上是一个类,包含了同django flask一样的数据字段 所有定义在模型中的方法都可以被模型本身的直接调用 现在编程范式有所改变,不应该直接访问模型,而是 ...

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

    实体间转换工具.其实也可以用Json来实现同名属性.异名属性(用JsonProperty指明)的自动转换 最新版本6.11 需要使用vs2013以上.vs2012下载新版 nuget会遇到问题.只能旧 ...

随机推荐

  1. POJ 2312Battle City(BFS-priority_queue 或者是建图spfa)

    /* bfs搜索!要注意的是点与点的权值是不一样的哦! 空地到空地的步数是1, 空地到墙的步数是2(轰一炮+移过去) 所以用到优先队列进行对当前节点步数的更新! */ #include<iost ...

  2. codeforces——Little Pony and Expected Maximum

    /* 我们枚举每次选择最大数值的情况:m个数, 投掷n次 最大值是1: 1种 2: 2^n-1 3: 3^n-2^n ..... m: m^n-(m-1)^n 所以最后的结果=sum((k/m)^n ...

  3. Docker之Linux UnionFS

    UnionFS UnionFS是一种为Linux,FreeBSD和NetBSD操作系统设计的把其他文件系统联合到一个联合挂载点的文件系统服务.它使用branch把不同文件系统的文件和目录"透 ...

  4. MemCache分布式缓存的一个bug

    Memcached分布式缓存策略不是由服务器端至支持的,多台服务器之间并不知道彼此的存在.分布式的实现是由客户端代码(Memcached.ClientLibrary)通过缓存key-server映射来 ...

  5. 开发人员看测试之细说JBehave

    上篇我们说到如何从Github上clone出一个JBehave项目,既是为了学习JBehava,也是为了熟悉下Github.从clone下来的项目看来,基本没什么问题,稍微捋一捋就可以运行,但是就cl ...

  6. Hadoop阅读笔记(一)——强大的MapReduce

    前言:来园子已经有8个月了,当初入园凭着满腔热血和一脑门子冲动,给自己起了个响亮的旗号“大数据 小世界”,顿时有了种世界都是我的,世界都在我手中的赶脚.可是......时光飞逝,岁月如梭~~~随手一翻 ...

  7. 15个来自 CodePen 的酷炫 CSS 动画效果【下篇】

    CodePen 是一个在线的前端代码编辑和展示网站,能够编写代码并即时预览效果.你在上面可以在线分享自己的 Web 作品,也可以欣赏到世界各地的优秀开发者在网页中实现的各种令人惊奇的效果. 今天这篇文 ...

  8. Java开发中的高频Collections用法总结与Java平台实现源代码查看方式

    一生二,二生三,三生万物,基础永远是一个计算机人的立身之本,相信看到这篇文章的人一般都知道数据结构这门课程,要不也不会找到我的这篇文章.数据结构这门课程的分析奠定了工程师对各种平台中的容器类,集合类的 ...

  9. 为什么是梯度下降?SGD

    在机器学习算法中,为了优化损失函数loss function ,我们往往采用梯度下降算法来进行优化.举个例子: 线性SVM的得分函数和损失函数分别为:                         ...

  10. SpringMVC——自定义拦截器、异常处理以及父子容器配置

    自定义拦截器: 一.若想实现自定义拦截器,需要实现 org.springframework.web.servlet.HandlerInterceptor 接口. 二.HandlerIntercepto ...