读书人

hibernate 多对1(Many-to-one)单向关联

发布时间: 2013-01-26 13:47:03 作者: rapoo

hibernate 多对一(Many-to-one)单向关联

多对一实例(Employee-Department)

1. E-R图:

2. 实体类:

Department类:

?hibernate 多对1(Many-to-one)单向关联hibernate 多对1(Many-to-one)单向关联
    package com.reiyen.hibernate.domainpublic class Department {private int id;private String name; //setter和getter方法....}

    ?

    ?Employee类:

    ?hibernate 多对1(Many-to-one)单向关联hibernate 多对1(Many-to-one)单向关联
      package com.reiyen.hibernate.domainpublic class Employee {private int id;private String name;private Department department;//setter和getter方法}

      ?

      ? 3. 实体映射文件:

      Department.hbm.xml如下:

      ?hibernate 多对1(Many-to-one)单向关联hibernate 多对1(Many-to-one)单向关联

        ?

        ?Employee.hbm.xml如下:

        ?hibernate 多对1(Many-to-one)单向关联hibernate 多对1(Many-to-one)单向关联

          ?

          ?<many-to-one name=”department” column=”depart_id” />这种缺省情况,
          hibernate会默认去department对象中查找主键值,因为hibernate默认的是外键对应另一个表中的主键的,
          如果想对应department中的其它属性,如”name”,则可以使用<many-to-one name=”department” column=”depart_id” property-ref=”name”/>也可以使用<many-to-one name=”department” />,这与 <many-to-one name=”depart” column=”depart_id” />的唯一区别就是它的column名也为department了,而不是depart_id.

          <many-to-one >元素建立了department属性和employee表的外键depart_id之间的映射.

          name: 设定待映射的持久化类的属性名,此外为employee类的department属性.

          column: 设定和持久化类的属性对应的表的外键,此外为employee表的外键depart_id.

          class(可选):设定持久化类的属性的类型,此处设定department的类型是Department类.

          not-null(可选):如果为true,表示department属性不能为null,该属性的默认值为false.当为true时,生成的employee表中depart_id外键会设置not-null约束,所以当Hibernate保存Employee对象时,会先检查它的department属性是否为null,如果为null,则会抛出异常.

          3. 将两个实体映射文件在hibernate.cfg.xml配置文件中注册:(hibernate.cfg.xml在我一篇文章:第一个Hibernate实例 中有)

          ?hibernate 多对1(Many-to-one)单向关联hibernate 多对1(Many-to-one)单向关联
            <mapping resource="com/reiyen/hibernate/domain/Department.hbm.xml" /><mapping resource="com/reiyen/hibernate/domain/Employee.hbm.xml" />

            ?4. 测试:

            ?hibernate 多对1(Many-to-one)单向关联hibernate 多对1(Many-to-one)单向关联
              public class Many2One {public static void main(String[] args) {Department depart = add();System.out.println("depart name: " + depart.getName());}static Department add() {Session s = null;Transaction tx = null;try {Department depart = new Department();depart.setName("department name");Employee employee = new Employee(); employee.setDepartment(depart); // 对象模型:建立两个对象的关联 employee.setName("employee name");s = HibernateUtil.getSession();tx = s.beginTransaction();s.save(depart); s.save(employee);tx.commit();return depart;} finally {if (s != null)s.close();}}}

              ?运行后,控制台打印信息如下:

              Hibernate: insert into Department (name) values (?)
              Hibernate: insert into Employee (name, depart_id) values (?, ?)
              depart name: department name

              查看Employee数据库表的创建语句如下:(注意红色部分)

              ??? DROP TABLE IF EXISTS `test`.`employee`;
              ??? CREATE TABLE? `test`.`employee` (
              ??? ? `id` int(11) NOT NULL AUTO_INCREMENT,
              ??? ? `name` varchar(255) DEFAULT NULL,
              ??? ? `depart_id` int(11) DEFAULT NULL,
              ??? ? PRIMARY KEY (`id`),
              ??? ? KEY `FK4AFD4ACEA3E9AC0F` (`depart_id`),
              ??? ? CONSTRAINT `FK4AFD4ACEA3E9AC0F` FOREIGN KEY (`depart_id`) REFERENCES `department` (`id`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

              ?表中插入记录如下:

              ?hibernate 多对1(Many-to-one)单向关联hibernate 多对1(Many-to-one)单向关联
                mysql> select * from employee;+----+---------------+-----------+| id | name | depart_id |+----+---------------+-----------+| 1 | employee name | 1 |+----+---------------+-----------+1 row in set (0.00 sec)mysql> select * from department;+----+-----------------+| id | name |+----+-----------------+| 1 | department name |+----+-----------------+1 row in set (0.00 sec)

                ?调换测试类两句程序的顺序,如下所示:

                ?

                ?hibernate 多对1(Many-to-one)单向关联hibernate 多对1(Many-to-one)单向关联
                  s.save(employee);s.save(depart);

                  则控制台的信息如下所示:(多了一条更新语句)

                  Hibernate: insert into Employee (name, depart_id) values (?, ?)
                  Hibernate: insert into Department (name) values (?)
                  Hibernate: update Employee set name=?, depart_id=? where id=?
                  depart name: department name

                  ?hibernate 多对1(Many-to-one)单向关联hibernate 多对1(Many-to-one)单向关联
                    employee.setDepartment(depart); // 对象模型:建立两个对象的关联

                    这句话很重要,如果没有这句话,则Department和Employee之间就没有任何关系了。

                    如果你在Employee.hbm.xml中配置了

                    <many-to-one name="department" column="depart_id" not-null="true"/>

                    则必须先保存department再保存employee,否则会抛出:

                    org.hibernate.PropertyValueException: not-null property references a null or transient value 异常!

                    查询测试:

                    ?hibernate 多对1(Many-to-one)单向关联hibernate 多对1(Many-to-one)单向关联
                      public class Many2One {public static void main(String[] args) {Department depart = add();Employee employee = query(1);// System.out.println("depart name:" + employee.getDepartment().getName()); // 2}static Employee query(int empId) {Session s = null;Transaction tx = null;try {s = HibernateUtil.getSession();tx = s.beginTransaction();Employee emp = (Employee) s.get(Employee.class, empId);System.out.println("depart name:" + emp.getDepartment().getName()); // 1 // System.out.println("depart class:" + emp.getDepartment().getClass()); // 4 //System.out.println("depart id:" + emp.getDepartment().getId()); //5 // Hibernate.initialize(emp.getDepartment()); // 3tx.commit();return emp;} finally {if (s != null)s.close();}}}

                      ?测试程序运行后,控制台打印出的sql如下:
                      Hibernate: select employee0_.id as id2_0_, employee0_.name as name2_0_, employee0_.depart_id as depart3_2_0_ from Employee employee0_ where employee0_.id=?
                      Hibernate: select department0_.id as id1_0_, department0_.name as name1_0_ from Department department0_ where department0_.id=?

                      depart? name:department name

                      当相关联的session没有关闭时,访问这些懒加载对象(代理对象)的属性(getId和getClass除外)时,hibernate会初始化这些代理,所以将Employee对象和Department对象都查询出来了。相当于在数据库中执行两次查询:
                      首先执行select * from employee where employee.id = ?
                      然后再执行select * from department where department.id = ?

                      ?

                      如果将测试程序中标记为2的语句前的注释去掉,同时把标记为1的语句注释掉,再运行刚会出现如下所示的异常:

                      org.hibernate.LazyInitializationException: could not initialize proxy - no Session

                      解决办法是把标记为3的语句前的注释去掉,即初始化懒加载的代理对象。(可以给query方法再传递一个参数,如boolean isInit,如果是true的话就初始化代理对象,即调用

                      ?hibernate 多对1(Many-to-one)单向关联hibernate 多对1(Many-to-one)单向关联
                        Hibernate.initialize(emp.getDepartment())

                        否则,就不初始化代理对象)。

                        ?

                        5.懒加载说明:

                        many-to-one(元素)懒加载:1).lazy!=false 2).fetch=select

                        能够懒加载的对象都是被改写过的代理对象,当相关联的session没有关闭时,访问这些懒加载对象(代理对象)的属性(getId和getClass除外)时,hibernate会初始化这些代理,或用Hibernate.initialize(proxy)来初始化代理对象;
                        当相关联的session关闭后,再访问懒加载的对象将会出现异常。

                        (1)把标记为1的语句注释掉,同时去掉标记为4的语句前面的注释,进行测试,控制台打印信息如下所示:

                        Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.depart_id as depart3_1_0_ from Employee employee0_ where employee0_.id=?
                        depart class:class com.itcast.hibernate.domain.Department$$EnhancerByCGLIB$$b412e7fa

                        说明实现了懒加载,它只查询出Employee对象,而没有去查询相应的Department对象;同时可以看出,返回的是改写过的代理对象,而不是实体类Department.

                        (2)把标记为1的语句注释掉,同时去掉标记为5的语句前面的注释,进行测试,控制台打印信息如下所示:

                        Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.depart_id as depart3_1_0_ from Employee employee0_ where employee0_.id=?
                        depart id:1

                        当相关联的session没有关闭时,访问这些懒加载对象(代理对象)getId和getClass属性,hibernate不会初始化这些代理。

读书人网 >开源软件

热点推荐