今天开始多对一单向关联检索策略。
先看一下多端域模型:
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 }
接下来是一端域模型:
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()三个方法,继承该基类的域模型就可以不需要再去实现了。
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,看一下网上这张图片,延迟和获取选项的等效注解:
在多对一中,@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 听雨轩