hibernate学习_关联映射

1.多对一(单向)关联映射(员工表-部门表):

  员工类:

package com.xudong.po;

public class Employee {
    private int id;
    private String name;
    private Department department;

    public int getId() {
        return id;
    }

    public void setId(int 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;
    }

}

  部门类:

package com.xudong.po;

public class Department {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

}

hibernate.cfg.xml:

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
    <property name="connection.url">jdbc:mysql:///test</property>
    <property name="connection.username">root</property>
    <property name="connection.password">root</property>
    <property name="connection.driver_class">
        com.mysql.jdbc.Driver
    </property>
    <property name="dialect">
        org.hibernate.dialect.MySQL5Dialect
    </property>
    <property name="format_sql">true</property>
    <property name="current_session_context_class">thread</property>
    <mapping resource="com/xudong/po/Item.hbm.xml" />




</session-factory>
</hibernate-configuration>

对象关系映射文件(Item.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.xudong.po">
  <class name="Department" table="t_dept">
    <id name="id">
      <generator class="native"/>
    </id>
    <property name="name"></property>
  </class>
 
  <class name="Employee" table="t_emp">
    <id name="id">
      <generator class="native"/>
    </id>
    <property name="name"></property>
    <many-to-one name="department"></many-to-one>
  </class>

</hibernate-mapping>

重点:<many-to-one name=""/>标签

 创建表的工具类:

package com.xudong.hibernate.util;

import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

public class Hbm2ddlUtil {

    
    public static void main(String[] args) {
       Configuration cfg = new Configuration().configure();
       SchemaExport se = new SchemaExport(cfg);
       se.create(true, true);
    }

}
运行后产生的sql:

 alter table t_emp
        drop
        foreign key FK68F5E7D76166533

    drop table if exists t_dept

    drop table if exists t_emp

    create table t_dept (
        id integer not null auto_increment,
        name varchar(255),
        primary key (id)
    )

    create table t_emp (
        id integer not null auto_increment,
        name varchar(255),
        department integer,
        primary key (id)
    )

    alter table t_emp
        add index FK68F5E7D76166533 (department),
     
   add constraint FK68F5E7D76166533
        foreign key (department)
        references t_dept (id)

往两张表中添加数据:

package com.xudong.hibernate.test;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.xudong.hibernate.util.HibernateUtil;
import com.xudong.po.Department;
import com.xudong.po.Employee;

public class T {

    
    public static void main(String[] args) {
       Session session = null;
       Transaction ts = null;
       try {
        session = HibernateUtil.getSession();
        ts = session.beginTransaction();
        Department department = new Department();
        department.setName("HR");
        
        Employee employee = new Employee();
        employee.setName("alice");
        employee.setDepartment(department);
        
        session.save(department);
        session.save(employee);
        System.out.println(employee.getDepartment().getName());
        ts.commit();
    } catch (HibernateException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        ts.rollback();
    }
    }
    
}
生成的sql:

Hibernate:
    insert
    into
        t_dept
        (name)
    values
        (?)
Hibernate:
    insert
    into
        t_emp
        (name, department)
    values
        (?, ?)
HR
    上面打印出的部门名称即是添加到t_dept表中的部门名称,我们用了这样一段代码 System.out.println(employee.getDepartment().getName());把它拿出来,内部实现机制是,先查到部门的id,再通过标签<many-to-one name="department"/>映射到Department类,通过部门id拿出满足条件的Department,再拿出部门类的名称。

    在上面的两条语句中session.save(department); session.save(employee); 如果不写前一句,直接写后一句,由于先有部门再有员工,此时会报一个异常注意到此时是一个多对一关系,倘若在多的一方,表现在映射文件上就是标签里的属性(cascade="save-update")<many-to-one name="department" cascade="save-update"/>,现在再运行就没有错误了,会自动级联创建表t_dept;

2.一对多(单向)关联映射(员工表与部门表):

package com.xudong.po;

public class Employee {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

}

部门表:

package com.xudong.po;

import java.util.Set;

public class Department {
    private int id;
    private String name;

    //之所以用Set,因为Set集合是唯一的
    private Set<Employee> emps;

    public Set<Employee> getEmps() {
        return emps;
    }

    public void setEmps(Set<Employee> emps) {
        this.emps = emps;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

}
对象关系映射文件:

<?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.xudong.po">

    <class name="Employee" table="t_emp">
        <id name="id">
            <generator class="native" />
        </id>
        <property name="name"></property>

    </class>
    <class name="Department" table="t_dept">
        <id name="id">
            <generator class="native" />
        </id>
        <property name="name"></property>
        <set name="emps">
            <key column="dept_id"></key>
            <one-to-many class="Employee" />
        </set>
    </class>


</hibernate-mapping>
创建表产生的sql:


    alter table t_emp
        drop
        foreign key FK68F5E7DA0313336

    drop table if exists t_dept

    drop table if exists t_emp

    create table t_dept (
        id integer not null auto_increment,
        name varchar(255),
        primary key (id)
    )

    create table t_emp (
        id integer not null auto_increment,
        name varchar(255),
        dept_id integer,
        primary key (id)
    )

    alter table t_emp
        add index FK68F5E7DA0313336 (dept_id),
        add constraint FK68F5E7DA0313336
        foreign key (dept_id)
        references t_dept (id)
添加元素到数据表中:

package com.xudong.hibernate.test;

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

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.xudong.hibernate.util.HibernateUtil;
import com.xudong.po.Department;
import com.xudong.po.Employee;

public class T {

    public static void main(String[] args) {
        Session session = null;
        Transaction ts = null;
        try {
            session = HibernateUtil.getSession();
            ts = session.beginTransaction();
            Department department = new Department();
            department.setName("HR");

            Employee employee1 = new Employee();
            employee1.setName("smith");

            Employee employee2 = new Employee();
            employee2.setName("jerry");

            Set<Employee> sets = new HashSet<Employee>();
            sets.add(employee1);
            sets.add(employee2);

            department.setEmps(sets);
            session.save(employee1);
            session.save(employee2);
            session.save(department);

            ts.commit();
        } catch (HibernateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            ts.rollback();
        }
    }

}
此时产生的sql:

Hibernate:
    insert
    into
        t_emp
        (name)
    values
        (?)
Hibernate:
    insert
    into
        t_emp
        (name)
    values
        (?)
Hibernate:
    insert
    into
        t_dept
        (name)
    values
        (?)
Hibernate:
    update
        t_emp
    set
        dept_id=?
    where
        id=?
Hibernate:
    update
        t_emp
    set
        dept_id=?
    where
        id=?

   这里为什么产生了两条update语句呢?

   在上面这段代码中,我们首先保存的是员工表的数据,由于此时部门表的信息尚未保存,在员工表中有一个字段名为dept_id暂且被赋值为null,当保存完员工表的信息后,部门表信息被保存,这时就有了dept_id,hibernate就会自动对上面员工表的信息(dept_id)进行更新!!!

   ->缺点:产生了多余的update语句(在少的一端进行维护);

   当代码变为在多的一端进行维护时,即将代码改为   session.save(department);  session.save(employee1);   session.save(employee2);就不会产生多余的update语句。

    此处映射文件中的<key column="dept_id"></key>,是在另一张表中添加外键dept_id;
    此外在<set>标签里有一项属性“inverse = true" ,这个属性不管代码是在多的一端或者在少的一端进行维护,都会反转到多的一端,不会产生额外的update语句。

产生的sql:

Hibernate:
    insert
    into
        t_emp
        (name)
    values
        (?)
Hibernate:
    insert
    into
        t_emp
        (name)
    values
        (?)
Hibernate:
    insert
    into
        t_dept
        (name)
    values
        (?)
3.一对一主键关联映射[双向](wife表与husband表):

Wife类:

package com.xudong.po;

public class Wife {
    private int id;
    private String name;
    private Husband husband;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Husband getHusband() {
        return husband;
    }

    public void setHusband(Husband husband) {
        this.husband = husband;
    }

}
Husband类:

package com.xudong.po;

public class Husband {
    private int id;
    private String name;
    private Wife wife;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Wife getWife() {
        return wife;
    }

    public void setWife(Wife wife) {
        this.wife = wife;
    }

}
对象关联映射文件:

<?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.xudong.po">

    <class name="Husband" table="t_hbd">
        <id name="id" column="hid">
            <generator class="foreign">
            <param name="property">Wife</param>
            </generator>
        </id>
        <property name="name"></property>
        <one-to-one name="wife" class="Wife" constrained="true"></one-to-one>

    </class>
    <class name="Wife" table="t_wife">
        <id name="id" column="wid">
            <generator class="native" />
        </id>
        <property name="name"></property>
        <one-to-one name="husband" class="Husband"></one-to-one>
    </class>


</hibernate-mapping>
创建表生成的sql:


  
   
alter table t_hbd
        drop
        foreign key FK68F685FCF6371FB

    drop table if exists t_hbd

    drop table if exists t_wife

    create table t_hbd (
        id integer not null,
        name varchar(255),
        primary key (id)
    )

    create table t_wife (
        id integer not null auto_increment,
        name varchar(255),
        primary key (id)
    )

    alter table t_hbd
        add index FK68F685FCF6371FB (id),
        add constraint FK68F685FCF6371FB
        foreign key (id)
        references t_wife (id)


通过Wife类查询Husband类里的name属性名:

package com.xudong.hibernate.test;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.xudong.hibernate.util.HibernateUtil;
import com.xudong.po.Husband;
import com.xudong.po.Wife;

public class T {

    public static void main(String[] args) {
        add();
        query(1);
    }

    static void add() {
        Session session = null;
        Transaction ts = null;
        try {
            session = HibernateUtil.getSession();
            ts = session.beginTransaction();

            Wife wife = new Wife();
            wife.setName("alice");

            Husband hbd = new Husband();
            hbd.setName("jack");

            hbd.setWife(wife);
            wife.setHusband(hbd);

            session.save(wife);
            session.save(hbd);

            ts.commit();
        } catch (HibernateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            ts.rollback();
        }
    }

    static void query(int id) {
        Session session = null;
        Transaction ts = null;
        try {
            session = HibernateUtil.getSession();
            ts = session.beginTransaction();
            Wife wife = (Wife) session.get(Wife.class, id);
            System.out.println(wife);
            System.out.println(wife.getHusband().getName());
            // Husband hbd = (Husband)session.get(Husband.class,id);
            // System.out.println(hbd.getWife().getName());

            ts.commit();
        } catch (HibernateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            ts.rollback();
        }
    }
}
运行结果:

Hibernate:
    insert
    into
        t_wife
        (name)
    values
        (?)
Hibernate:
    insert
    into
        t_hbd
        (name, id)
    values
        (?, ?)
Hibernate:
    select
        wife0_.id as id1_1_,
        wife0_.name as name1_1_,
        husband1_.id as id0_0_,
        husband1_.name as name0_0_
    from
        t_wife wife0_
    left outer join
        t_hbd husband1_
            on wife0_.id=husband1_.id
    where
        wife0_.id=?
com.xudong.po.Wife@1e879e

//查询出的Husband名称jack
jack
通过Husband类查询Wife类里的name属性名:

static void query(int id) {
        Session session = null;
        Transaction ts = null;
        try {
            session = HibernateUtil.getSession();
            ts = session.beginTransaction();
            Husband husband = (Husband)session.get(Husband.class,id);
            System.out.println(husband.getWife().getName());
            // Husband hbd = (Husband)session.get(Husband.class,id);
            // System.out.println(hbd.getWife().getName());

            ts.commit();
        } catch (HibernateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            ts.rollback();
        }
    }

 

运行结果:

Hibernate:
    select
        husband0_.id as id0_0_,
        husband0_.name as name0_0_
    from
        t_hbd husband0_
    where
        husband0_.id=?
Hibernate:
    select
        wife0_.id as id1_1_,
        wife0_.name as name1_1_,
        husband1_.id as id0_0_,
        husband1_.name as name0_0_
    from
        t_wife wife0_
    left outer join
        t_hbd husband1_
            on wife0_.id=husband1_.id
    where
        wife0_.id=?
alice
    constrained属性只能在<one-to-one>标签中使用,如果constrained="true"表明当前这张表有外键与关联表相对应;

    标签<generator>里的class="foreign",表明当前这张表的主键不是自动生成的,而是依靠另一张表的主键生成的,其中在此标签内有<param name="property"></param>标签,这里面的值代表了当前表的主键依赖于哪个类生成(对应于数据库中哪个表生成);

4.一对一外键关联映射(双向):

对象关联映射文件:

<?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.xudong.po">

    <class name="Husband" table="t_hbd">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name"></property>
        <one-to-one name="wife" property-ref="husband"></one-to-one>

    </class>
    <class name="Wife" table="t_wife">
        <id name="id">
            <generator class="native" />
        </id>
        <property name="name"></property>
        <many-to-one name="husband" column="hid" unique="true"></many-to-one>
    </class>


</hibernate-mapping>
 <one-to-one name="wife" property-ref="husband"></one-to-one>标签中的property-ref属性用来指明关联类的一个属性,与关联表的外键相对应;

5.多对多关联映射(Teacher与Student):

Teacher类:

package com.xudong.po;

import java.util.Set;

public class Teacher {
    private int id;
    private String name;
    private Set<Student> students;

    public int getId() {
        return id;
    }

    public void setId(int 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类:

package com.xudong.po;

import java.util.Set;

public class Student {
    private int id;
    private String name;
    private Set<Teacher> teachers;

    public int getId() {
        return id;
    }

    public void setId(int 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;
    }

}

对象关联映射文件:

<?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.xudong.po">

    <class name="Teacher" table="t_teacher">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name"></property>
        <set name="students" table="teacher_student">
          <key column="tid"></key>
          <many-to-many class="Student" column="sid"></many-to-many>
        </set>

    </class>
    <class name="Student" table="t_student">
        <id name="id">
            <generator class="native" />
        </id>
        <property name="name"></property>
        <set name="teachers" table="teacher_student" inverse="true">
          <key column="sid"></key>
          <many-to-many class="Teacher" column="tid"></many-to-many>
        </set>
    </class>


</hibernate-mapping>


创建表生成的sql:


    alter table teacher_student
        drop
        foreign key FK2E2EF2DE3F9A82DA

    alter table teacher_student
        drop
        foreign key FK2E2EF2DE59CDD042

    drop table if exists t_student

    drop table if exists t_teacher

    drop table if exists teacher_student

    create table t_student (
        id integer not null auto_increment,
        name varchar(255),
        primary key (id)
    )

    create table t_teacher (
        id integer not null auto_increment,
        name varchar(255),
        primary key (id)
    )

    create table teacher_student (
        tid integer not null,
        sid integer not null,
        primary key (sid, tid)
    )

    alter table teacher_student
        add index FK2E2EF2DE3F9A82DA (sid),
        add constraint FK2E2EF2DE3F9A82DA
        foreign key (sid)
        references t_student (id)

    alter table teacher_student
        add index FK2E2EF2DE59CDD042 (tid),
        add constraint FK2E2EF2DE59CDD042
        foreign key (tid)
        references t_teacher (id)
       多对多关联映射需要创建中间表,标签<set>中的属性table用来指明中间表的名称,两次指明的表名称要相同,标签<key>用来指明需要在中间表里设置的外键名称;

      向表中添加数据:

package com.xudong.hibernate.test;

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

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.xudong.hibernate.util.HibernateUtil;
import com.xudong.po.Student;
import com.xudong.po.Teacher;

public class T {

    public static void main(String[] args) {
        add();
    }

    static void add() {
        Session session = null;
        Transaction ts = null;
        try {
            session = HibernateUtil.getSession();
            ts = session.beginTransaction();

            Set<Teacher> sets = new HashSet<Teacher>();
            Teacher t1 = new Teacher();
            t1.setName("t1");
            sets.add(t1);

            Teacher t2 = new Teacher();
            t2.setName("t2");
            sets.add(t2);

            Set<Student> sets1 = new HashSet<Student>();
            Student s1 = new Student();
            s1.setName("s1");
            sets1.add(s1);

            Student s2 = new Student();
            s2.setName("s2");
            sets1.add(s2);

            t1.setStudents(sets1);
            t2.setStudents(sets1);

            session.save(s1);
            session.save(s2);
            session.save(t1);
            session.save(t2);

            ts.commit();
        } catch (HibernateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            ts.rollback();
        }
    }

}

mysql中的三张表:

      其中映射文件里的<set>标签里有个属性inverse="true",是在Student类下设置的,表示关联关系由Teacher类来维护,只有当主控方对象状态发生改变时(这里指的就是Teacher类),hibernate会根据对象状态的改变来同步更新,即产生相应的sql语句;当代码执行到下面两句(t1.setStudents(sets1)、t2.setStudents(sets1))时,Teacher类的对象状态发生了改变,产生4条sql语句;如果inverse="true"这项属性写在Teacher类下,那么执行完插入数据的操作后,多对多关系的中间表里没有任何数据,因为Student的状态并未发生改变,hibernate就不会产生insert语句,来更新中间表;

 

 


 

        

 

 

posted @ 2013-10-26 14:03  xudong91  阅读(201)  评论(0编辑  收藏  举报