持久层框架--hibernate(4)

一.多对多双向关联

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

持久化类Student

 1 持久化类Student.java
 2
 3 package com.edu.many2many;
 4
 5 import java.util.HashSet;
 6 import java.util.Set;
 7
 8 public class Student {
 9
10     private Integer id;
11     private String name;
12
13     //关联关系
14     Set<Course> courses = new HashSet<Course>();
15     public Integer getId() {
16         return id;
17     }
18     public void setId(Integer id) {
19         this.id = id;
20     }
21     public String getName() {
22         return name;
23     }
24     public void setName(String name) {
25         this.name = name;
26     }
27     public Set<Course> getCourses() {
28         return courses;
29     }
30     public void setCourses(Set<Course> courses) {
31         this.courses = courses;
32     }
33
34
35 }

持久化类Course

 1 持久化类Course.java
 2
 3 package com.edu.many2many;
 4
 5 import java.util.HashSet;
 6 import java.util.Set;
 7
 8 public class Course {
 9
10     private Integer id;
11     private String name;
12
13     //关联关系
14     Set<Student> students = new HashSet<Student>();
15
16     public Integer getId() {
17         return id;
18     }
19     public void setId(Integer id) {
20         this.id = id;
21     }
22     public String getName() {
23         return name;
24     }
25     public void setName(String name) {
26         this.name = name;
27     }
28     public Set<Student> getStudents() {
29         return students;
30     }
31     public void setStudents(Set<Student> students) {
32         this.students = students;
33     }
34
35
36 }

Student.hbm.xml对象关系映射文件

 1 Student.hbm.xml映射文件
 2
 3 <?xml version="1.0" encoding="UTF-8"?>
 4 <!DOCTYPE hibernate-mapping PUBLIC
 5     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 6     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 7 <hibernate-mapping package="com.edu.many2many">
 8     <class name="Student">
 9         <id name="id">
10             <generator class="increment"/>
11         </id>
12
13         <property name="name"/>
14
15         <!-- 关联属性
16             cascade属性:级联操作默认值为none
17                   save-update:级联保存或更新
18                   delete:级联删除
19                   all
20             inverse="true":默认值为false。主控方
21                            true 反转控制权,变为被控方,没有维护关联关系的权利。
22         -->
23         <!-- courses  和Course类    多对多
24              在多对多关系中,映射两端关系表的名称必须要相同
25          -->
26         <set name="courses" table="stu_cou" >
27             <key column="sid"/>
28             <many-to-many class="Course" column="cid"/>
29         </set>
30     </class>
31
32
33 </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 Course.hbm.xml映射文件
 2
 3 <?xml version="1.0" encoding="UTF-8"?>
 4 <!DOCTYPE hibernate-mapping PUBLIC
 5     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 6     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 7 <hibernate-mapping package="com.edu.many2many">
 8     <class name="Course" table="course">
 9         <id name="id">
10             <generator class="increment"/>
11         </id>
12
13         <property name="name"/>
14
15         <!-- 映射关联属性 -->
16         <!-- students  和 Student类 多对多
17             name:  关联属性的名字
18             class: 关联类的类名
19             column: 数据库外键字段的名字
20             table:关系表的名称
21
22             多对多关联映射 中cascade="delete" 注意使用:会级联删除对端表的记录
23         -->
24         <set name="students" table="stu_cou" >
25             <key column="cid"/>
26             <many-to-many class="Student" column="sid"/>
27         </set>
28     </class>
29
30 </hibernate-mapping>

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

hibernate.cfg.xml映射文件

 1 hibernate.cfg.xml映射文件
 2
 3 <?xml version="1.0" encoding="UTF-8"?>
 4 <!DOCTYPE hibernate-configuration PUBLIC
 5     "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 6     "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
 7 <hibernate-configuration>
 8 <session-factory>
 9     <!-- 配置数据库连接的基本信息 -->
10     <property name="hibernate.connection.driver_class">
11         oracle.jdbc.driver.OracleDriver
12     </property>
13     <property name="hibernate.connection.url">
14         jdbc:oracle:thin:@localhost:1521:XE
15     </property>
16     <property name="hibernate.connection.username">lihengyu</property>
17     <property name="hibernate.connection.password">lihengyu</property>
18
19     <!-- 数据库的方言 使用的是哪种数据库 -->
20     <property name="hibernate.dialect">
21         org.hibernate.dialect.Oracle10gDialect
22     </property>
23     <!-- 显示sql语句 -->
24     <property name="hibernate.show_sql">true</property>
25     <!-- 自动创建数据库表
26         none:默认值  有表就使用,没表不创建
27         create:每次都创建新表
28         update: 有表就使用,没表创建。如果持久化类及映射文件发生改变,则发生alter语句修改表结构。
29     -->
30     <property name="hibernate.hbm2ddl.auto">update</property>
31
32     <!-- 添加映射文件 -->
33     <mapping resource="com/edu/many2many/Course.hbm.xml" />
34     <mapping resource="com/edu/many2many/Student.hbm.xml" />
35
36
37 </session-factory>
38
39
40 </hibernate-configuration>

TestHibernate.java测试代码

  1 TestHibernate .java
  2
  3 package com.edu.many2many;
  4
  5 import org.hibernate.SessionFactory;
  6 import org.hibernate.Transaction;
  7 import org.hibernate.cfg.Configuration;
  8 import org.hibernate.classic.Session;
  9 import org.junit.Test;
 10
 11 /**
 12  * 使用单元测试工具,测试hibernate 的增删改查(CRUD)操作
 13  *
 14  * @author Administrator
 15  *
 16  */
 17 public class TestHibernate {
 18
 19     private static SessionFactory sf;
 20     static {
 21         // 1. 加载配置文件
 22         Configuration cfg = new Configuration();
 23         cfg.configure("com/edu/many2many/hibernate.cfg.xml");
 24
 25         // 2. 获得SessionFactory
 26         sf = cfg.buildSessionFactory();
 27     }
 28
 29
 30     /**
 31      *  保存用户
 32      *
 33      */
 34     @Test
 35     public void save() {
 36
 37
 38         Session session = sf.openSession();
 39         Transaction tran = session.beginTransaction();
 40
 41         Course c1 = new Course();
 42         c1.setName("体育");
 43         Course c2 = new Course();
 44         c2.setName("音乐");
 45
 46         Student s1 = new Student();
 47         s1.setName("张三");
 48         Student s2 = new Student();
 49         s2.setName("李四");
 50
 51         //维护关联关系
 52         c1.getStudents().add(s1);
 53         c1.getStudents().add(s2);
 54
 55         c2.getStudents().add(s1);
 56         c2.getStudents().add(s2);
 57         /**
 58          * 如果程序中,需要从关联两端同时维护关系,则其中一端必须交出控制权
 59          * 变为被控方,被控方不在维护关联关系
 60          */
 61         s1.getCourses().add(c1);
 62         s1.getCourses().add(c2);
 63
 64         s2.getCourses().add(c1);
 65         s2.getCourses().add(c2);
 66
 67         session.save(c1);
 68         session.save(c2);
 69         session.save(s1);
 70         session.save(s2);
 71
 72         tran.commit();
 73         session.close();
 74     }
 75
 76     /**
 77      *  查询
 78      *
 79      */
 80     @Test
 81     public void find() {
 82
 83
 84         Session session = sf.openSession();
 85         Transaction tran = session.beginTransaction();
 86
 87         //谁选择了id=1的课程
 88         Course c1 = (Course) session.get(Course.class, 1);
 89         for (Student stu : c1.getStudents()) {
 90             System.out.println(stu.getName());
 91         }
 92
 93         tran.commit();
 94         session.close();
 95     }
 96
 97     //删除1号课程
 98     @Test
 99     public void delete() {
100
101
102         Session session = sf.openSession();
103         Transaction tran = session.beginTransaction();
104
105
106         Course c1 = (Course) session.get(Course.class, 1);
107
108         session.delete(c1);
109
110         //如果student是被控方,不能级联删除外表记录
111         /*Student s1 = (Student) session.get(Student.class, 1);
112         session.delete(s1);*/
113
114         tran.commit();
115         session.close();
116     }
117 }

(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,则都不会向连接表中插入记录而只是向两表中插入记录(两者都认为对方会维持关联关系)

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

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

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

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

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

时间: 2024-11-16 11:44:21

持久层框架--hibernate(4)的相关文章

持久层框架hibernate相关概念

hibernate为全自动的持久层框架(framework): 1.作用:把内存中的活跃对象永远的保存在关系型数据库中. 2.O/R/M原理:O-->object 对象,R---> relational关系型数据库,M--->mapping映射 为了解决应用程序中的对象和关系型数据库中的表的不匹配而提出的一个解决方案. 3.新版本hibernate4中怎么得到session工厂从而创建连接对象 Configuration cfg = new Configuration().configu

持久层框架--hibernate(3)

一:关联关系 1.关联关系的方向可分为单向关联和双向关联 单向关联:假设存在两张表province表和City表,如果在应用的业务逻辑中,仅需要每个province实例能够查询得到其对应的City实例,而City实例并不需要查询得到其对应的province实例:或者反之. 双向关联:既需要每个province实例能够查询得到其对应的City实例,City实例也需要查询得到其对应的province实例. 2.关联的数量,根据拥有被关联对象的个数确定 多对一(many to one):如用户和组 学

持久层框架--hibernate(2)

一 .持久化对象的oid 映射为数据库表的主键,唯一不重复 当数据库表中的主键为代理主键时,持久化对象的oid 要交给hibernate来维护(避免重复) 当数据库中表的主键为自然主键时,持久化对象的oid 要由程序本身来维护 主键生成策略(生成持久化oid的方式): 1. increment 带走+1 由hibernate来维护oid的值, 优点:与底层数据库类型无关 缺点:只适用于单线程对数据库的访问 2. identity +1带走 优点:适合多用户访问 缺点:由于+1操作由数据库完成,所

Hibernate数据库持久层框架

Hibernate是一种Java语言下的对象关系映射解决方案. 它是使用GNU宽通用公共许可证发行的自由.开源的软件.它为面向对象的领域模型到传统的关系型数据库的映射,提供了一个使用方便的框架.Hibernate也是目前Java开发中最为流行的数据库持久层框架,现已归JBOSS所有. 它的设计目标是将软件开发人员从大量相同的数据持久层相关编程工作中解放出来.无论是从设计草案还是从一个遗留数据库开始,开发人员都可以采用Hibernate. Hibernate不仅负责从Java类到数据库表的映射(还

[笔面] Hibernate等持久层框架应用面试

Hibernate等持久层框架应用 1.Hibernate框架的工作流程a. 读取并解析配置文件b.读取并解析映射信息,创建SessionFactoryc.打开Sesssiond.创建事务Transatione.持久化操作f.提交事务g.关闭Sessionh.关闭SesstionFactory 2.Hibernate框架中的核心接口有哪些,这些接口的具体功能是什么?核心接口有:session,sessionFactory,transaction,query,configuration.a) Se

Hibernate: 数据持久层框架

Hibernate 是一种Java语言下的对象关系映射解决方案. 它是使用GNU宽通用公共许可证发行的自由.开源的软件.它为面向对象的领域模型到传统的关系型数据库的映射,提供了一个使用方便的框架.Hibernate也是目前Java开发中最为流行的数据库持久层框架,现已归JBOSS所有.基于LGPL V2.1协议发布. 它的设计目标是将软件开发人员从大量相同的数据持久层相关编程工作中解放出来.无论是从设计草案还是从一个遗留数据库开始,开发人员都可以采用Hibernate. Hibernate不仅负

MyBatis持久层框架使用总结

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis . 2013年11月迁移到Github,MyBatis的Github地址:https://github.com/mybatis/mybatis-3. iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架.iBATIS提供的持久层框架包括SQL Maps和Dat

JPA规范及其它持久层框架

JPA规范及其它持久层框架 JPA是一种规范,而hibernate是JPA的一种实现 JPA全称为Java Persistence API ,Java持久化API是Sun公司在Java EE 5规范中提出的Java持久化接口.JPA吸取了目前Java持久化技术的优点,旨在规范.简化Java对象的持久化工作.使用JPA持久化对象,并不是依赖于某一个ORM框架. JPA是目前比较流行的一种ORM技术之一,所以他拥有ORM技术的各种特点,当然他还有自己的一些优势: 1 标准化 JPA 是 JCP 组织

MyBatis持久层框架使用总结 转载

MyBatis持久层框架使用总结 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis . 2013年11月迁移到Github,MyBatis的Github地址:https://github.com/mybatis/mybatis-3. iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架.iBATIS提供的持久