hibernate映射

参考: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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值