hibernate映射

来源:互联网 发布:acrobat dc mac 编辑:程序博客网 时间:2024/04/29 01:49

参考:http://www.cnblogs.com/kubixuesheng/p/5300437.html

多对一单向外键关联关系

多对一关联时多方持有一方的引用。比如学生和班级,多个学生对应一个班级。
单向多对一关联中,(1)多方需要持有一方的引用,(2)多方(学生类)需要额外的配置,需要对持有一方引用的注解<many-to-one> (3)多方必须保留一个不带参数的构造器 一方班级类无需做任何多余操作
<many-to-one>具有以下属性:
name:一方的引用名
class:一方对应的持久化类
column:外键的列名
fetch:抓取策略
cascade:级联操作,有以下取值
- all 对所有操作进行级联操作
- save-update执行保存和更新操作时进行级联操作
- delete执行删除操作时进行级联操作
- none对所有操作不进行级联操作

多方:学生类和其对应的hbm.xml(因为hibernate具有二级缓存,缓存会将对象写进缓存,所以一般要实现serializable接口)

public class Student implements Serializable{    private int sid;    private String sname;    private String sex;    private Grade grade;//持有多方的引用    public Grade getGrade() {        return grade;    }    public void setGrade(Grade grade) {        this.grade = grade;    }    public int getSid() {        return sid;    }    public void setSid(int sid) {        this.sid = sid;    }    public String getSname() {        return sname;    }    public void setSname(String sname) {        this.sname = sname;    }    public String getSex() {        return sex;    }    public void setSex(String sex) {        this.sex = sex;    }    public Student() {        // TODO Auto-generated constructor stub    }    public Student(String sname, String sex) {        super();        this.sname = sname;        this.sex = sex;    }}
<?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"><!--     Mapping file autogenerated by MyEclipse Persistence Tools--><hibernate-mapping>    <class name="entity.Student" table="student">        <id name="sid" type="java.lang.Integer">            <column name="sid" />            <generator class="increment" />        </id>        <property name="sname" type="java.lang.String">            <column name="sname" length="20" not-null="true"/>        </property>        <property name="sex" type="java.lang.String">            <column name="sex"></column>        </property>        <many-to-one name="grade" class="entity.Grade" column="gid" cascade="all"></many-to-one>    </class></hibernate-mapping>

一方:班级类(无需多余定义)

public class Grade implements Serializable {    private int gid;    private String gname;    private String gdesc;    public int getGid() {        return gid;    }    public void setGid(int gid) {        this.gid = gid;    }    public String getGname() {        return gname;    }    public void setGname(String gname) {        this.gname = gname;    }    public String getGdesc() {        return gdesc;    }    public void setGdesc(String gdesc) {        this.gdesc = gdesc;    }    public Grade(String gname, String gdesc) {        super();        this.gname = gname;        this.gdesc = gdesc;    }    public Grade() {        // TODO Auto-generated constructor stub    }}
<?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"><!--     Mapping file autogenerated by MyEclipse Persistence Tools--><hibernate-mapping>    <class name="entity.Grade" table="grade">        <id name="gid" type="java.lang.Integer">            <column name="gid" />            <generator class="increment" />        </id>        <property name="gname" type="java.lang.String">            <column name="gname" length="20" not-null="true"/>        </property>        <property name="gdesc" type="java.lang.String">            <column name="gdesc" length="50"></column>        </property>    </class></hibernate-mapping>

HibernateSessionFactoryUtil类用于获得sessionFactory和获得Session

public class HibernateSessionFactoryUtil {        private static SessionFactory sessionFactory;        private static Session session;        static {            //创建Configuration对象,读取hibernate.cfg.xml文件,完成初始化            Configuration cof = new Configuration().configure();            //ServiceRegistry 是 Service 的注册表, 它为Service提供了一个统一的加载 /初始化 /存放 /获取机制.            ServiceRegistryBuilder ssrb = new ServiceRegistryBuilder()                    .applySettings(cof.getProperties());            ServiceRegistry ssr=ssrb.buildServiceRegistry();            sessionFactory=cof.buildSessionFactory(ssr);        }        public static SessionFactory getSessionFactory(){            return sessionFactory;        }        public static Session getSession(){            session=sessionFactory.openSession();            return session;        }        public static void closeSession(Session session){            if(session!=null)                session.close();        }    }

下面进行测试

public class Test {    public static void main(String[] args) {        add();    }    public static void add(){        Grade g=new Grade("java开发","java开发一班");        Student stu1=new Student("张三","女");        Student stu2=new Student("李四","男");        Session session=HibernateSessionFactoryUtil.getSession();        Transaction tx=session.beginTransaction();        stu1.setGrade(g);        stu2.setGrade(g);        //由于进行了级联操作,只需save学生类,班级类会自动存储        session.save(stu1);        session.save(stu2);        tx.commit();    HibernateSessionFactoryUtil.closeSession(session);    }

hibernate.cfg.xml加上:

<mapping resource="entity/Grade.hbm.xml" /><mapping resource="entity/Student.hbm.xml"/>

执行结果:
控制台输出:
Hibernate: select max(sid) from student
Hibernate: select max(gid) from grade
Hibernate: insert into grade (gname, gdesc, gid) values (?, ?, ?)
Hibernate: insert into student (sname, sex, gid, sid) values (?, ?, ?, ?)
Hibernate: insert into student (sname, sex, gid, sid) values (?, ?, ?, ?)

数据库添加的记录:
student表
这里写图片描述

grade表
这里写图片描述

一对多单向外键关联

当类与类建立了关联,程序能很方便的从一个对象导航到另一个或一组与之关联的对象,有了student对象,就可以通过student对象得到grade的信息–student.getGrade(),对于班级对象,如果想要得到学生的信息,怎么办呢?这时候可以反过来控制,一方控制多方,接下来进行一对多单向外键关联

(1)一方持有多方的集合(2)一方的hbm.xml有<set>配置,其含有子标签<one-to-many><key>子标签(3)不管是一对多还是多对一,多方都要保留无参构造器

多方:grade增加了Set<Stuent>

public class Grade implements Serializable {    private int gid;    private String gname;    private String gdesc;    //在一方定义多方的集合    private Set<Student> students=new HashSet<Student>();    public int getGid() {        return gid;    }    public void setGid(int gid) {        this.gid = gid;    }    public String getGname() {        return gname;    }    public void setGname(String gname) {        this.gname = gname;    }    public String getGdesc() {        return gdesc;    }    public void setGdesc(String gdesc) {        this.gdesc = gdesc;    }    public Set<Student> getStudents() {        return students;    }    public void setStudents(Set<Student> students) {        this.students = students;    }    public Grade(String gname, String gdesc) {        super();        this.gname = gname;        this.gdesc = gdesc;    }    public Grade() {        // TODO Auto-generated constructor stub    }}

Grade.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"><!--     Mapping file autogenerated by MyEclipse Persistence Tools--><hibernate-mapping>    <class name="entity.Grade" table="grade">        <id name="gid" type="java.lang.Integer">            <column name="gid" />            <generator class="increment" />        </id>        <property name="gname" type="java.lang.String">            <column name="gname" length="20" not-null="true"/>        </property>        <property name="gdesc" type="java.lang.String">            <column name="gdesc" length="50"></column>        </property>      <set name="students" table="student" inverse="false" cascade="save-update">            <key column="gid"></key>            <one-to-many class="entity.Student"/>        </set>    </class>    <!-- 添加了set,name表示Grade类中Set变量的名字,table表示对应的数据库中的表,inverse指定关联关系的控制方向,默认由one方控制,也就是在多方的inverse属性,有关这个理解见我另一篇博文 -->

student类不做任何添加,在这里省去
下面执行test

public class Test {    public static void main(String[] args) {        add();    }    public static void add(){        Grade g=new Grade("java开发","java开发一班");        Student stu1=new Student("张三","女");        Student stu2=new Student("李四","男");        Session session=HibernateSessionFactoryUtil.getSession();        Transaction tx=session.beginTransaction();        g.getStudents().add(stu1);        g.getStudents().add(stu2);        session.save(g);        tx.commit();        HibernateSessionFactoryUtil.closeSession(session);    }

控制台输出:
Hibernate: select max(gid) from grade
Hibernate: select max(sid) from student
Hibernate: insert into grade (gname, gdesc, gid) values (?, ?, ?)
Hibernate: insert into student (sname, sex, sid) values (?, ?, ?)
Hibernate: insert into student (sname, sex, sid) values (?, ?, ?)
Hibernate: update student set gid=? where sid=?
Hibernate: update student set gid=? where sid=?

数据库数据也载入正常

总结:多对一的时候,多方设置EAGER(积极加载),一方设置LAZY(懒加载),也就是说,如果是多对一,多方控制一方,那么多方设置积极加载,一方无需多余配置,反过来,如果是一对多关系,一方控制多方,那么一方设置懒加载,多方无需多余配置,但是不论哪种,多方都显式加上一个不带参数的构造器。(其实对于懒加载与否,这些配置是默认的)

一对多双向关联

其实类似之前的一对一双向外键关联,也是互相持有对方的引用,故也叫双向一对多自身关联。多方持有一方的引用,反过来,一方也持有多方的集合

多对多单向关联

在多对多关联关系中,显然不能互相持有对方主键做外键,那么就需要用到一个新的表作为中间表进行映射

举例:学生和老师
创建表teacher和teachers_students

create table teacher(    -> tid int primary key,    -> tname varchar(20)); create table teachers_students(    -> sid int not null,    -> tid int not null);    alter table teachers_students add primary key (sid,tid);

Student类新增:

public Set<Teacher> getTeachers() {        return teachers;    }    public void setTeachers(Set<Teacher> teachers) {        this.teachers = teachers;    }    public Grade getGrade() {        return grade;    }

Student.hbm.xml新增

<!-- table设置中间表 --><set name="teachers" table="teachers_students" cascade="all" inverse="false"><!-- key设置本对象在中间表的外键sid --><key column="sid" /><!-- tid设置对方的表(老师)在中间表的外键tid --><many-to-many class="entity.Teacher" column="tid"></many-to-many></set>

老师不做多余配置

public class Teacher implements Serializable{    private int tid;    private String tname;    public int getTid() {        return tid;    }    public void setTid(int tid) {        this.tid = tid;    }    public String getTname() {        return tname;    }    public void setTname(String tname) {        this.tname = tname;    }    public Teacher(String tname) {        super();        this.tname = tname;    }    public Teacher() {        super();        // TODO Auto-generated constructor stub    }}
<?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"><!--     Mapping file autogenerated by MyEclipse Persistence Tools--><hibernate-mapping>    <class name="entity.Teacher" table="teacher">        <id name="tid" type="java.lang.Integer">            <column name="tid" />            <generator class="increment" />        </id>        <property name="tname" type="java.lang.String">            <column name="tname" length="20" not-null="true"/>        </property>    </class></hibernate-mapping>

测试:

Student s=new Student("学生1","女");        Set<Teacher> teas=s.getTeachers();        Teacher t1=new Teacher("张三");        Teacher t2=new Teacher("李四");        Teacher t3=new Teacher("王五");        teas.add(t1);        teas.add(t2);        teas.add(t3);        Session session=HibernateSessionFactoryUtil.getSession();        Transaction tx=session.beginTransaction();        session.save(s);        tx.commit();    HibernateSessionFactoryUtil.closeSession(session);

控制台输出
Hibernate: select max(sid) from student
Hibernate: select max(tid) from teacher
Hibernate: insert into student (sname, sex, gid, sid) values (?, ?, ?, ?)
Hibernate: insert into teacher (tname, tid) values (?, ?)
Hibernate: insert into teacher (tname, tid) values (?, ?)
Hibernate: insert into teacher (tname, tid) values (?, ?)
Hibernate: insert into teachers_students (sid, tid) values (?, ?)
Hibernate: insert into teachers_students (sid, tid) values (?, ?)
Hibernate: insert into teachers_students (sid, tid) values (?, ?)

数据库存储正常

多对多双向外键关联

和之前的类似,是互相持有对方的集合,双方持有对方的集合对象

Teacher类添加:

    private Set<Student> students=new HashSet<Student>();    public Set<Student> getStudents() {        return students;    }    public void setStudents(Set<Student> students) {        this.students = students;    }

Teacher.hbm.xml添加

 <set name="students" table="teachers_students" cascade="all" inverse="false">            <key column="tid"></key>            <many-to-many class="entity.Student" column="sid"></many-to-many>        </set>

关联关系的优缺点

用关联关系,就可以直接操作内存中的对象,不用每次都查询数据库,会提高效率;而且域模型真实反映了客观世界的关系,但是缺点就是建立复杂的关联关系会给程序开发带来麻烦,当修改一个对象时,会牵连其它的对象

问题小结

(1)注意在多对一/一对多关系里:多方必须保留一个不带参数的构造器!
(2)如果没有设置级联ALL,那么需要在保存的时候先保存班级,在保存学生,否则出错: object references an unsaved transient instance - save the transient instance before flushing:
(3)多对一时候,多方设置EAGER加载,一对多的时候,一方设置LAZY加载
(4)多对多关联,多方需要保留一个无参构造器。

0 0
原创粉丝点击