Hibernate第四篇【集合映射、一对多和多对一】
前言
前面的我们使用的是一个表的操作,但我们实际的开发中不可能只使用一个表的…因此,本博文主要讲解关联映射
集合映射
需求分析:当用户购买商品,用户可能有多个地址。
数据库表
我们一般如下图一样设计数据库表,一般我们不会在User表设计多个列来保存地址的。因为每个用户的地址个数都不一的,会造成数据冗余
- 创建两张数据表,一张保存着用户的信息,一张保存着地址的信息。地址表使用外键来引用用户表
 
实体
由于地址只是使用String类型来保存着,那么我们直接使用一个User对象就可以了
public class User {
    private String id;
    private String username;
    private String password;
    private Set<String> address;
    //各种setter和getter
映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--在domain包下-->
<hibernate-mapping package="zhongfucheng.domain">
    <class name="User" table="user">
        <!--主键映射-->
        <id name="id" column="id" >
            <generator class="native"/>
        </id>
        <!--普通字段映射-->
        <property name="username" column="username"></property>
        <property name="password" column="password"></property>
        <!--
             Set:
                name: 映射集合的名称
                table:集合的属性要映射到哪张表(address)
             key:
                column:指定要映射的表(address)中的外键列
                element:要映射的表的其他字段
                    类型一定要指定!
        -->
        <set name="address" table="address">
            <key column="user_id"></key>
            <element column="addr" type="string"></element>
        </set>
    </class>
</hibernate-mapping>
测试
package zhongfucheng.domain;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
/**
 * Created by ozc on 2017/5/6.
 */
public class App {
    public static void main(String[] args) {
        //创建对象
        User user = new User();
        user.setUsername("123");
        user.setPassword("1234");
        user.getAddress().add("广州");
        //获取加载配置管理类
        Configuration configuration = new Configuration();
        //加载User的映射文件!
        configuration.configure().addClass(User.class);
        //创建Session工厂对象
        SessionFactory factory = configuration.buildSessionFactory();
        //得到Session对象
        Session session = factory.openSession();
        //使用Hibernate操作数据库,都要开启事务,得到事务对象
        Transaction transaction = session.getTransaction();
        //开启事务
        transaction.begin();
        session.save(user);
        //提交事务
        transaction.commit();
        //关闭Session
        session.close();
    }
}
List集合映射配置
既然我们现在已经会了如何配置Set集合了,List集合又怎么配置呢??
想一下,List集合和Set集合有什么区别…List集合是有序的,因此要多配置一个列来维护数据的有序性!
        <list name="address" table="address">
            <key column="user_id"></key>
            <!--index是关键字,不能使用!!!!-->
            <list-index column="index"></list-index>
            <element column="addr" type="string"></element>
        </list>
Map集合映射配置
Map集合和Collection集合的区别就是键值对模型,那么在配置的时候多一个key即可!
        <map name="address" table="address">
            <key column="user_id"  ></key>
            <map-key type="string" column="short"></map-key>
            <element type="string" column="addr"></element>
        </map>
一对多和多对一
上面我们讲解了集合映射是怎么配置的,那集合装载的元素有没有可能是对象呢??而不是简单的String类型..那个就太多了!一般地,我们集合装载的都是对象,而不是简单的String,如果我们的装载在集合的数据有很多类型,那么String就不能用了!…
需求:部门与员工之间的关系
- 一个部门有多个员工; 【一对多】
 - 多个员工,属于一个部门 【多对一】
 
设计数据库表
员工表应该使用一个外键来记住部门表。这样才可以维护员工和部门之间的关系
设计实体
部门实体要使用一个集合来记住所有的员工,员工要使用一个对象引用着部门
- Dept.java
 
package zhongfucheng.domain;
import java.util.HashSet;
import java.util.Set;
/**
 * Created by ozc on 2017/5/6.
 */
public class Dept {
    private int id ;
    private Set<Employee> set = new HashSet<>();
    private String deptName;
    public String getDeptName() {
        return deptName;
    }
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public Set<Employee> getSet() {
        return set;
    }
    public void setSet(Set<Employee> set) {
        this.set = set;
    }
}
- Employee.java
 
package zhongfucheng.domain;
/**
 * Created by ozc on 2017/5/6.
 */
public class Employee {
    private int id;
    private String empName;
    private double salary;
    private Dept dept;
    public Dept getDept() {
        return dept;
    }
    public void setDept(Dept dept) {
        this.dept = dept;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
}
映射分析
我们在写映射配置文件之前,分析一下怎么写。以部门映射配置文件为例…
现在使用了一个Set集合来维护与员工的关系,Set集合的类型是员工对象…因此在映射文件中需要以下几点
- 映射集合属性的名称(employees)
 - 映射集合对应的数据表(employee)
 - 对应的数据表的外键字段(dept_id)
 - 集合中的元素类型(Employee)【通过这个类型,Hibernate就可以找到对应类型的映射文件,从而得到对应的信息!】
 
部门映射配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--在domain包下-->
<hibernate-mapping package="zhongfucheng.domain">
    <class name="Dept" table="dept">
        <id column="id" name="id">
            <generator class="native">
            </generator>
        </id>
        <!--普通字段映射-->
        <property name="deptName" column="deptname"></property>
        <!--维护关系的是Set集合,对应employee表-->
        <set  cascade="save-update" name="set" table="employee">
            <!--employee的外键列是dept_no-->
            <key column="dept_no"></key>
            <!--一个部门对应多个员工,集合的类型是Employee-->
            <one-to-many class="Employee" ></one-to-many>
        </set>
    </class>
</hibernate-mapping>
员工映射配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--在domain包下-->
<hibernate-mapping package="zhongfucheng.domain">
    <class name="Employee" table="employee">
        <id column="id" name="id">
            <generator class="native">
            </generator>
        </id>
        <!--普通字段数据-->
        <property name="empName" column="empName"></property>
        <property name="salary" column="salary"></property>
        <!--Hibernate这个标签可看成在当前表中设置一个外键dept_no-->
        <many-to-one name="dept" class="Dept" column="dept_no"></many-to-one>
    </class>
</hibernate-mapping>
在“一”的一方测试
package zhongfucheng.domain;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
/**
 * Created by ozc on 2017/5/6.
 */
public class App {
    public static void main(String[] args) {
        //创建对象
        Dept dept = new Dept();
        dept.setDeptName("开发部");
        Employee zs = new Employee();
        zs.setEmpName("张珊");
        zs.setSalary(1111);
        Employee ls = new Employee();
        ls.setEmpName("李四");
        ls.setSalary(2222);
        //添加关系
        dept.getSet().add(zs);
        dept.getSet().add(ls);
        //获取加载配置管理类
        Configuration configuration = new Configuration();
        //加载User的映射文件!
        configuration.configure().addClass(Dept.class).addClass(Employee.class);
        //创建Session工厂对象
        SessionFactory factory = configuration.buildSessionFactory();
        //得到Session对象
        Session session = factory.openSession();
        //使用Hibernate操作数据库,都要开启事务,得到事务对象
        Transaction transaction = session.getTransaction();
        //开启事务
        transaction.begin();
        session.save(dept);
        session.save(zs);
        session.save(ls);
        //提交事务
        transaction.commit();
        //关闭Session
        session.close();
    }
}
Hibernate执行了5条SQL语句
在“多”的一方测试
package zhongfucheng.domain;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
/**
 * Created by ozc on 2017/5/6.
 */
public class App {
    public static void main(String[] args) {
        //创建对象
        Dept dept = new Dept();
        dept.setDeptName("开发部");
        Employee zs = new Employee();
        zs.setEmpName("张珊");
        zs.setSalary(1111);
        Employee ls = new Employee();
        ls.setEmpName("李四");
        ls.setSalary(2222);
        //维护关系
        zs.setDept(dept);
        ls.setDept(dept);
        //获取加载配置管理类
        Configuration configuration = new Configuration();
        //加载User的映射文件!
        configuration.configure().addClass(Dept.class).addClass(Employee.class);
        //创建Session工厂对象
        SessionFactory factory = configuration.buildSessionFactory();
        //得到Session对象
        Session session = factory.openSession();
        //使用Hibernate操作数据库,都要开启事务,得到事务对象
        Transaction transaction = session.getTransaction();
        //开启事务
        transaction.begin();
        session.save(dept);
        session.save(zs);
        session.save(ls);
        //提交事务
        transaction.commit();
        //关闭Session
        session.close();
    }
}
Hibernate执行了3条SQL
一对多和多对一总结
在一对多与多对一的关联关系中,保存数据最好的通过多的一方来维护关系,这样可以减少update语句的生成,从而提高hibernate的执行效率!
- 配置一对多与多对一, 这种叫“双向关联”
 - 只配置一对多, 叫“单项一对多”
 - 只配置多对一, 叫“单项多对一”
 
值得注意是:配置了哪一方,哪一方才有维护关联关系的权限!
- 当我在部门中不配置员工的关联关系了,那么在操作部门的时候就不能得到员工的数据了【也就是:在保存部门时,不能同时保存员工的数据】
 
Hibernate第四篇【集合映射、一对多和多对一】的更多相关文章
- NHibernate 集合映射基础(第四篇) - 一对一、 一对多、多对多小示例
		
映射文件,用于告诉NHibernate数据库里的表.列于.Net程序中的类的关系.因此映射文件的配置非常重要. 一.一对一 NHibernate一对一关系的配置方式使用<one-to-one&g ...
 - Hibernate之关联映射(一对多和多对一映射,多对多映射)
		
~~~接着之前的Hibernate框架接着学习(上篇面试过后发现真的需要学习以下框架了,不然又被忽悠让去培训.)~~~ 1:Hibernate的关联映射,存在一对多和多对一映射,多对多映射: 1.1: ...
 - Hibernate之关联关系映射(一对多和多对一映射,多对多映射)
		
~~~接着之前的Hibernate框架接着学习(上篇面试过后发现真的需要学习一下框架了,不然又被忽悠让去培训.)~~~ 1:Hibernate的关联映射,存在一对多和多对一映射,多对多映射: 1.1: ...
 - (转)Hibernate关联映射——一对多(多对一)
		
http://blog.csdn.net/yerenyuan_pku/article/details/70152173 Hibernate关联映射——一对多(多对一) 我们以客户(Customer)与 ...
 - Hibernate  集合映射 一对多多对一 inverse属性 +  cascade级联属性  多对多 一对一 关系映射
		
1 . 集合映射 需求:购物商城,用户有多个地址. // javabean设计 // javabean设计 public class User { private int userId; privat ...
 - hibernate学习四(关系映射一对一与组件映射)
		
一.关系映射简介 在数据库中,表与表的关系,仅有外键.但使用hibernate后,为面向对象的编程,对象与对象的关系多样化:如 一对一,一对多,多对多,并具有单向和双向之分. 开始练习前,复制上一次项 ...
 - Hbase篇--HBase中一对多和多对多的表设计
		
一.前述 今天分享一篇关于HBase的一对多和多对多的案例的分析. 二.具体案例 案例一.多对多 人员-角色 人员有多个角色 角色优先级 角色有多个人员 人员 删除添加角色 角 ...
 - SSH框架之Hibernate第四篇
		
Hibernate中有两套实现数据库数据操作的方式 : hibernate前3天讲解的都是 : hibernate自己的操作方式(纯XML配置文件的方式) 另一种方式是基于JPA的操作方式(通过注解的 ...
 - Mybatis之旅第四篇-输入输出映射
		
一.引言 在日常开发用到mybatis时,因为实际的开发业务场景很复杂,不论是输入的查询条件,还是返回的结果,经常是需要根据业务来定制,这个时候我们就需要自己来定义一些输入和输出映射 二.parame ...
 
随机推荐
- noip普及组2004 FBI树
			
FBI树 描述 我们可以把由"0"和"1"组成的字符串分为三类:全"0"串称为B串,全"1"串称为I串,既含" ...
 - 使用EasyWechat快速开发微信支付
			
前期准备: 申请微信支付后, 会收到2个参数, 商户id,和商户key.注意,这2个参数,不要和微信的参数混淆.微信参数: appid, appkey, token支付参数: merchant_id( ...
 - Bash中的测试——test, [], [[]], (())
			
转自: http://blog.csdn.net/u013961718 https://www.shiyanlou.com/courses/running test 和 [ ] test是一条内置命令 ...
 - 【Maven】 install:install-file
			
install jar to local fs mvn .jar -DgroupId=com.bonc -DartifactId=licenseVerify-.jar -Dversion= -Dpac ...
 - 8.8.1 Super关键字
			
Super关键字 1.super不是引用类型,super中存储的不是内存地址,super指向的不是父类对象. 2.super代表的是当前子类对象中的父类型特征. //通过子类的构造方法去调用父类的构造 ...
 - innerHTML innerText的使用和区别
			
document对象中有innerHTML.innerText这两个属性,都是获取document对象文本内容,但使用起来还是有区别的: 1) innerHTML设置或获取标签所包含的HTML+文本信 ...
 - spring学习笔记2---MVC处理器映射(handlerMapping)三种方式(附源码)
			
一.根据Beanname访问controller: 在springmmvc-servlet.xml的配置handlermapping中加入beanname,通过该beanname找到对应的contro ...
 - golang channel无缓冲通道会发生阻塞的验证
			
公司搞了午间技术par,本周我讲的主题是关于无缓冲通道channel是否会发生阻塞,并进行了验证. go语言中channel分为无缓冲通道和有缓冲通道两种 channel提供了一种在goroutine ...
 - 我的acm vim 备忘
			
一.從命令到編輯模式 a :当前单词后面插入Appendi :当前位置插入Inserto :当前行下新开一行插入Open new lineA :当前行尾插入AppendI :当前行首插入InsertO ...
 - [2017-07-18]ELK安装笔记
			
ELK ElasticSearch LogStash Kibana Server:CentOS 7 采用RPM导入官方源方式进行安装 rpm --import https://artifacts.el ...