Hibernate检索策略之5.2多对一单向关联检索策略——Hibernate4究竟怎么玩

今天开始多对一单向关联检索策略。

先看一下多端域模型:

 1 package com.bao.sample.retrieve.strategy.umto;
 2 
 3 import javax.persistence.Entity;
 4 import javax.persistence.FetchType;
 5 import javax.persistence.GeneratedValue;
 6 import javax.persistence.GenerationType;
 7 import javax.persistence.Id;
 8 import javax.persistence.JoinColumn;
 9 import javax.persistence.ManyToOne;
10 import javax.persistence.Table;
11 
12 import org.hibernate.annotations.Cascade;
13 import org.hibernate.annotations.Proxy;
14 
15 import com.bao.sample.base.domain.BaseDomain;
16 
17 /**
18  * 
19  * @Description 多对一单向关联--单向关联多端
20  * @author Bob [email protected]
21  * @date 2012-8-27
22  */
23 @Proxy(lazy = false)
24 //默认是false,是否延迟加载类级别实例
25 @Entity
26 @Table(name = "t_studentum")
27 public class StudentUM extends BaseDomain {
28 
29     private static final long serialVersionUID = 1L;
30 
31     private Integer id;
32 
33     private String name;
34 
35     private ClassUO classUO;
36 
37     @Id
38     @GeneratedValue(strategy = GenerationType.AUTO)
39     public Integer getId() {
40         return id;
41     }
42 
43     public void setId(Integer id) {
44         this.id = id;
45     }
46 
47     public String getName() {
48         return name;
49     }
50 
51     public void setName(String name) {
52         this.name = name;
53     }
54 
55     @ManyToOne(fetch = FetchType.EAGER)
56     @JoinColumn(name = "classid", nullable = false)
57     @Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE)
58     public ClassUO getClassUO() {
59         return classUO;
60     }
61 
62     public void setClassUO(ClassUO classUO) {
63         this.classUO = classUO;
64     }
65 
66     public StudentUM() {
67         super();
68     }
69 
70     public StudentUM(String name, ClassUO classUO) {
71         super();
72         this.name = name;
73         this.classUO = classUO;
74     }
75 
76 }

接下来是一端域模型:

Hibernate检索策略之5.2多对一单向关联检索策略——Hibernate4究竟怎么玩Hibernate检索策略之5.2多对一单向关联检索策略——Hibernate4究竟怎么玩ClassUO
 1 package com.bao.sample.retrieve.strategy.umto;
 2 
 3 import javax.persistence.GeneratedValue;
 4 import javax.persistence.GenerationType;
 5 import javax.persistence.Id;
 6 import javax.persistence.Table;
 7 
 8 import javax.persistence.Entity;
 9 
10 import com.bao.sample.base.domain.BaseDomain;
11 
12 /**
13  * 
14  * @Description 多对一单向关联--单向关联一端
15  * @author Bob [email protected]
16  * @date 2012-8-27
17  */
18 @Entity
19 @Table(name = "t_classuo")
20 public class ClassUO extends BaseDomain {
21 
22     private static final long serialVersionUID = 1L;
23 
24     private Integer id;
25     private String name;
26 
27     @Id
28     @GeneratedValue(strategy = GenerationType.AUTO)
29     public Integer getId() {
30         return id;
31     }
32 
33     public void setId(Integer id) {
34         this.id = id;
35     }
36 
37     public String getName() {
38         return name;
39     }
40 
41     public void setName(String name) {
42         this.name = name;
43     }
44 
45     public ClassUO() {
46         super();
47     }
48 
49     public ClassUO(String name) {
50         super();
51         this.name = name;
52 
53     }
54 
55 }

再看一下PO基类,基类通过反射实现了equals(),hasCode()和toString()三个方法,继承该基类的域模型就可以不需要再去实现了。

Hibernate检索策略之5.2多对一单向关联检索策略——Hibernate4究竟怎么玩Hibernate检索策略之5.2多对一单向关联检索策略——Hibernate4究竟怎么玩BaseDomain
 1 package com.bao.sample.base.domain;
 2 
 3 import java.io.Serializable;
 4 
 5 import org.apache.commons.lang3.builder.EqualsBuilder;
 6 import org.apache.commons.lang3.builder.HashCodeBuilder;
 7 import org.apache.commons.lang3.builder.ToStringBuilder;
 8 
 9 /**
10  * @Description PO基类实现Serializable接口,以便JVM可以序列化PO实例.利用反射实现了equals(),hasCode()和toString()方法
11  * @author Bob [email protected]
12  * @date 2012-7-25
13  */
14 public class BaseDomain implements Serializable {
15 
16     private static final long serialVersionUID = 1L;
17 
18     public boolean equals(Object obj) {
19         return EqualsBuilder.reflectionEquals(this, obj);
20     }
21 
22     public int hasCode() {
23         return HashCodeBuilder.reflectionHashCode(this);
24     }
25 
26     public String toString() {
27         return ToStringBuilder.reflectionToString(this);
28     }
29 }

 在讲解检索策略之前呢,先说一下@Entity和@Table注解,前者是标识该类为域模型,在applicationContext.xml中进行如下配置后,程序便会扫描该包下及其子包下的类注解,不同的注解表示不同的组件。

1 <context:component-scan base-package="com.bao.sample.retrieve.strategy.umto" />

@Table与数据库表对应,其属性name的值即为该域模型对应数据表的名称。

先讲@ManyToOne,看一下网上这张图片,延迟和获取选项的等效注解:

Hibernate检索策略之5.2多对一单向关联检索策略——Hibernate4究竟怎么玩

在多对一中,@ManyToOne(fetch = FetchType.EAGER)即表示,多端立即加载、一端迫切连接。

下面看一下测试的方法(数据表数据仍然是5.1节中的数据):

 1     /**
 2      * @Description @ManyToOne(fetch = FetchType.EAGER)时检索关联对象
 3      * 
 4      */
 5     @Test
 6     public void fetchStudentByEager() {
 7         StudentUMService studentUMService = (StudentUMService) applicationContext
 8                 .getBean("studentUMService");
 9         StudentUM studentUM = studentUMService.getById(1);
10 
11         ClassUO classUO = studentUM.getClassUO();
12         System.out.println("迫切连接时关联对象类型:" + classUO.getClass());
13 
14         System.out.println(classUO.getId());//①
15         System.out.println("------迫切的分割线------");
16         System.out.println(classUO.getName());//②
17 
18     }

控制台输出的信息:

 1 Hibernate: 
 2     select
 3         studentum0_.id as id10_1_,
 4         studentum0_.classid as classid10_1_,
 5         studentum0_.name as name10_1_,
 6         classuo1_.id as id9_0_,
 7         classuo1_.name as name9_0_ 
 8     from
 9         t_studentum studentum0_ 
10     inner join
11         t_classuo classuo1_ 
12             on studentum0_.classid=classuo1_.id 
13     where
14         studentum0_.id=?
15 迫切连接时关联对象类型:class com.bao.sample.retrieve.strategy.umto.ClassUO
16 1
17 ------迫切的分割线------
18 class one

由此可以看出,检索策略使用迫切连接,多端和一端对象都不是代理类的实例。

当@ManyToOne(fetch = FetchType.EAGER)时,检索的sql语句使用left out join或者inner join方式,具体采用何种方式,根据@JoinColumn(name = "classid", nullable = false)中的nullable属性决定,当nullable=true(默认),会使用left outer join;当nullable=false,会使用inner join.

可以对比一下延迟获取:

 1     /**
 2      * @Description @ManyToOne(fetch=FetchType.LAZY)时检索关联对象
 3      * 
 4      */
 5     @Test
 6     public void fetchStudentByLazy() {
 7         StudentUMService studentUMService = (StudentUMService) applicationContext
 8                 .getBean("studentUMService");
 9         StudentUM studentUM = studentUMService.getById(1);
10 
11         ClassUO classUO = studentUM.getClassUO();
12         System.out.println(classUO.getId());
13 
14         System.out.println("------延迟的分割线------");
15         System.out.println(classUO.getName());
16     }

控制台输出结果:

 1 Hibernate: 
 2     select
 3         studentum0_.id as id10_0_,
 4         studentum0_.classid as classid10_0_,
 5         studentum0_.name as name10_0_ 
 6     from
 7         t_studentum studentum0_ 
 8     where
 9         studentum0_.id=?
10 1
11 ------延迟的分割线------

并有错误提示:org.hibernate.LazyInitializationException: could not initialize proxy - no Session。
已经熟悉了该错误了吧,session关闭了,再去查询时报错。

在解释一下:

当@ManyToOne(fetch=FetchType.LAZY),即从OrderUM导航CustomerUO采用延迟加载时,导航的CustomerUO为一个代理对象,只初始化CustomerUO的标识符,若此时再去调用CustomerUO其他属性时,hibernate会去数据库中进行真正的查询,而getCurrentSesion随事务的提交已经关闭,所以会报org.hibernate.LazyInitializationException: could not initialize proxy - no Session.不能初始化代理类的错误.

今天就到这里。2012-08-30 00:10:23 听雨轩 

转载于:https://www.cnblogs.com/geyifan/archive/2012/08/29/2662924.html