• 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 (?, ?)
  • 相关阅读:
    datatime,time,string转换和format格式化处理
    迭代器和生成器进一步的认识
    对数据结构的新认识
    python StringIO中的 read()与 getvalue()
    git 分支策略
    js词法分析
    js作用域
    注解
    MapReduce过程详解(基于hadoop2.x架构)
    指数基金
  • 原文地址:https://www.cnblogs.com/heml/p/4732498.html
Copyright © 2020-2023  润新知