Hibernate学习笔记

Hibernate集合映射

  1. Set 
  2. List
  3. Map
  4. Array
  5. Bag

Set集合

set元素不允许重复,常见的有HashSet、TreeSet、LinkedHashSet,HashSet中的元素是没有顺序的,TreeSet和LinkedHashSet中的元素是有序的

实体类User
package com.hml.domain;

import java.util.Set;

public class User {

    private int id;
    private String name;
    private Set<String> address;// set集合存放地址

    public int getId() {
        return id;
    }

    public Set<String> getAddress() {
        return address;
    }

    public void setAddress(Set<String> address) {
        this.address = address;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

User.hbm.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">
    <class name="User" table="t_user">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>
        <property name="name" column="name"></property>

        <!-- 
            name: set集合对象
            table:集合对象数据存储的表
            key:外键的名称,对应的数据是User的主键
            element:set集合中存储的数据
         -->
        <set name="address" table="t_user_address">
            <key column="userId"></key>
            <element column="address" type="string"></element>
        </set>
    </class>

</hibernate-mapping>

注意:hibernate中的集合在实体类中声明时应该声明为接口类型,因为Hibernate内部对集合类型进行了特殊处理。

 

Set集合hbm的配置文件如上,如果需要排序可以在set节点添加sort属性或者order-by属性指定排序,但是此时要求的Set集合是有序的集合,如:TreeSet。sort是内存排序,order-by是数据库排序,建议使用order-by。

 

List集合

List集合是有序的集合

实体类User

package com.hml.domain;

import java.util.List;

public class User {

    private int id;
    private String name;
    private List<String> address; // List集合

    public int getId() {
        return id;
    }

    public List<String> getAddress() {
        return address;
    }

    public void setAddress(List<String> address) {
        this.address = address;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

User.hbm.xml文件配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">
    <class name="User" table="t_user">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>
        <property name="name" column="name"></property>

        <!-- 
            name: set集合对象
            table:集合对象数据存储的表
            key:外键的名称,对应的数据是User的主键
            element:set集合中存储的数据
            list-index:指定集合元素的顺序
         -->
        <list name="address" table="t_user_address">
           <key column="userId"></key>
           <list-index column="idx"></list-index>
           <element column="address" type="string"></element>
        </list>
    </class>

</hibernate-mapping>

 List集合的配置和Set类似,只是多了一个指定元素顺序的节点list-index

集合Map

Map集合存储key value 值对

User实体类

package com.hml.domain;

import java.util.Map;

public class User {

    private int id;
    private String name;
    private Map<String, String> address;

    public int getId() {
        return id;
    }

    public Map<String, String> getAddress() {
        return address;
    }

    public void setAddress(Map<String, String> address) {
        this.address = address;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

User.hbm.xml文件的配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">
    <class name="User" table="t_user">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>
        <property name="name" column="name"></property>

        <!-- 
            name: Map集合对象
            table:集合对象数据存储的表
            key:外键的名称,对应的数据是User的主键
            element:Map集合中存储的数据
            map-key:Map集合中key的映射
         -->
        <map name="address" table="t_user_address">
            <key column="userid"></key>
            <map-key column="key_" type="string"></map-key>
            <element column="address" type="string"></element>
        </map>
    </class>

</hibernate-mapping>

Array数组的使用和List集合差不多只是使用的节点是array而已,Bag存储的元素可重复,但是是无序的,配置使用的是bag节点,实体中使用的是list集合。

 

多对一/一对多关系

这里用员工和部门举例,部门和员工的关系是一对多的关系,员工和部门的关系就是多对一的关系。

类图

Employee实体

package com.hml.domain;

public class Employee {

    private Integer id;
    private String name;
    private Department department;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

}

Department实体

package com.hml.domain;

import java.util.HashSet;
import java.util.Set;

public class Department {

    private Integer id;
    private String name;
    private Set<Employee> employees = new HashSet<Employee>();

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(Set<Employee> employees) {
        this.employees = employees;
    }

}

Employee.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">
    <class name="Employee" table="t_employee">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>
        <property name="name" column="name"></property>

        <!-- 
            many-to-one:表示多对一的关系
            column:指定外键的名称,可以省略,如果省略,则外键名称和name一致
            class:指定一的一方是哪个类,可以省略,系统可以自动推断
         -->
        <many-to-one name="department" column="departmentid" class="Department"></many-to-one>
    </class>

</hibernate-mapping>

Department.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">
    <class name="Department" table="t_department">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>
        <property name="name" column="name"></property>

        <!-- 
             这里和普通集合的配置是一样的,只不过这里的key的column是多的一方的many-to-one column的值,
             element元素变成了one-to-many,class的值是多的一方的全限定名称
         -->
        <set name="employees" >
            <key column="departmentid"></key>
            <one-to-many class="Employee"/>
        </set>
        
    </class>

</hibernate-mapping>

 

上面的例子是 多对一/一对多 的双向映射关系,也就是说两遍都可以维护关系。一般情况下为了效率,会让一的一方放弃维护关系,这个时候我们可以使用如下的配置

Department.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">
    <class name="Department" table="t_department">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>
        <property name="name" column="name"></property>

        <!-- 
             这里和普通集合的配置是一样的,只不过这里的key的column是多的一方的many-to-one column的值,
             element元素变成了one-to-many,class的值是多的一方的全限定名称
             
             inverse: 默认为false,代表维护关系,如果为true则表示放弃维护关系,这时关系由另外一方维护
         -->
        <set name="employees" inverse="true">
            <key column="departmentid"></key>
            <one-to-many class="Employee"/>
        </set>
        
    </class>

</hibernate-mapping>

 inverse:如果一的一方放弃维护关联关系,也就是inverse="true",那么对于一的一方进行删除,如果多的一方有关联的数据,那么会抛出异常,对于数据的加载不会存在影响

一对多和多对一可分为,单向和双向关系,单向是指有一方不能查询到对方,双向是指,彼此都可以查到对方。如果我们把Department employees属性去掉,那么对应关系就是一对多单向关联关系。

多对多的对应关系

 

Student实体类

package com.hml.domain;

import java.util.HashSet;
import java.util.Set;

public class Student {

    private Integer id;
    private String name;
    private Set<Teacher> teachers = new HashSet<Teacher>();;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Teacher> getTeachers() {
        return teachers;
    }

    public void setTeachers(Set<Teacher> teachers) {
        this.teachers = teachers;
    }

}

Teacher实体类

package com.hml.domain;

import java.util.HashSet;
import java.util.Set;

public class Teacher {
    private Integer id;
    private String name;
    private Set<Student> students = new HashSet<Student>();

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Student> getStudents() {
        return students;
    }

    public void setStudents(Set<Student> students) {
        this.students = students;
    }

}

Student.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">
    <class name="Student" table="t_student">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>
        <property name="name" column="name"></property>

        <!-- 
            table:中间表的名称
            key:中间表的外键,对应本对象的id
            many-to-many:说明多对多的关系,class指明关联对象,column中间表中相对于关联对象的外键
         -->
        <set name="teachers" table="t_student_tearcher" inverse="false">
            <key column="studentId"></key>
            <many-to-many class="Teacher" column="teacherId"></many-to-many>
        </set>
    </class>

</hibernate-mapping>

Teacher.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">
    <class name="Teacher" table="t_teacher">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>
        <property name="name" column="name"></property>
        
        <!-- 
            table:中间表的名称
            key:中间表的外键,对应本对象的id
            many-to-many:说明多对多的关系,class指明关联对象,column中间表中相对于关联对象的外键
            inverse: true表示不维护关联关系,多对多的映射建议一方放弃维护关联关系
            cascade:指定级联关系,这里设置为delete是级联删除的意思,也就是说删除teacher的同时级联删除该老师的学生,
                    可以避免由于不能维护关系而删除对象报异常,cascade有多种取值,实际使用的时候按照需求设置
         -->
        <set name="students" table="t_student_tearcher" inverse="true" cascade="delete">
            <key column="teacherId"></key>
            <many-to-many class="Student" column="studentId"></many-to-many>
        </set>
    </class>

</hibernate-mapping>

 多对多的对应关系也分为单向和双向,单向就是通过一方查询不到另外一方。

一对一映射关系 

    基于主键的一对一映射关系:有一张表的主键就是外键

    基于外键的一对一映射关系:在一张表中存在一个外键,这个外键是唯一的

 

基于外键的一对一映射关系

表结构:

Person表:

IdCard表:

IdCard表中有一个外键personid对应了person表中的主键。

 

Person类:

package com.hml.domain;


public class Person {
    private Integer id;
    private String name;

    private IdCard idCard; // 关联的身份证

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public IdCard getIdCard() {
        return idCard;
    }

    public void setIdCard(IdCard idCard) {
        this.idCard = idCard;
    }

    @Override
    public String toString() {
        return "[Person:id=" + id + ", name=" + name + "]";
    }

}

IdCard类

package com.hml.domain;

public class IdCard {
    private Integer id;
    private String number;

    private Person person; // 关联的公民

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    public String toString() {
        return "[IdCard:id=" + id + ", number=" + number + "]";
    }

}

Person.hbm.xml映射文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">
    
    <class name="Person" table="person">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name"/>
        
        <!-- idCard属性,IdCard类型。
            表达的是本类与IdCard的一对一。
            采用基于外键的一对一映射方式,本方无外键方。
            property-ref属性:
                写的是对方映射中外键列对应的属性名。    
         -->
        <one-to-one name="idCard" class="IdCard" property-ref="person"/>
        
    </class>
    
</hibernate-mapping>

IdCard.hbm.xml映射文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">
    
    <class name="IdCard" table="idCard">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="number"/>
        
        <!-- person属性,Person类型。
            表达的是本类与Person的一对一。
            采用基于外键的一对一映射方式,本方有外键方。 -->
        <many-to-one name="person" class="Person" column="personId" unique="true"></many-to-one>
        
    </class>
    
</hibernate-mapping>

基于外键的一对一映射其中一张表中会存在一个外键,这个外键是另外一张表的主键。在没有外键的映射文件中我们使用标签one-to-one来映射,name属性是映射的java对象的属性, class指定了映射的类, property-ref指定另外一方java类中映射为外键的属性。在有主键的一方通过many-to-one标签进行映射,该映射需要注意的是必须加上unique="true"

 

基于主键的一对一映射:

Person.hbm.xml配置文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">
    
    <class name="Person" table="person">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name"/>
        
        <!-- idCard属性,IdCard类型。
            表达的是本类与IdCard的一对一。
            采用基于主键的一对一映射方式,本方无外键方。
         -->
        <one-to-one name="idCard" class="IdCard"></one-to-one>
        
    </class>
    
</hibernate-mapping>

IdCard.hbm.xml配置文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.hml.domain">

    <class name="IdCard" table="idCard">
        <id name="id">
            <!-- 当使用基于主键的一对一映射时, 有外键方的主键生成策略一定要是foreign。 
参数property: 生成主键值时所根据的属性对象。
--> <generator class="foreign"> <param name="property">person</param> </generator> </id> <property name="number" /> <!-- person属性,Person类型。 表达的是本类与Person的一对一。
采用基于主键的一对一映射方式,本方有外键方。 constrained="true"强制加上外键约束
--> <one-to-one name="person" class="Person" constrained="true"></one-to-one> </class> </hibernate-mapping>

 

基于主键的映射两边属性都使用one-to-one进行映射,不过在有外键的一方有些不同,有外键的一方主键生成策略一定是foreign,还有就是one-to-one标签中,constrained="true",代表必须加上外键约束。基于主键的映射在插入数据的时候,先插入没有外键的一方的数据,然后把主键当成另外一方的主键进行数据插入:

Hibernate: insert into person (name) values (?)
Hibernate: insert into idCard (number, id) values (?, ?)

 

posted @ 2015-08-22 15:50  天之涯0204  阅读(215)  评论(0编辑  收藏  举报