今天开始Hibernate 4的检索策略。
Hibernate的检索策略有立即检索、延迟检索和迫切左连接检索三种方式。
检索策略 | 类级别 | 关联级别 |
立即检索 | 立即加载指定的对象 | 立即加载与指定对象相关联的对象 |
延迟检索 | 延迟加载指定的对象 | 延迟加载与指定对象相关联的对象 |
迫切左外连接 | 不适用 | 通过左外连接加载与指定对象相关联的对象 |
以上是三种检索策略分别在类级别和关联级别中的不同点的说明。下面以Student与Class类多对一单向关联,举例对类级别中的检索策略进行说明。项目采用分层的方式,接近实际的开发流程。(为了方便查看放在了同一包下)
在类级别检索中只需要用到一端的实体类、service和dao层即可,在此以多端为例:
以下图分别是包的结构和表结构及数据:
其中dao层和service层只需继承基类即可,具体代码可参考(待补充)无需其他代码。
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 hehe198504@126.com 21 * @date 2012-8-27 22 */ 23 @Proxy(lazy = true) 24 @Entity 25 @Table(name = "t_studentum") 26 public class StudentUM extends BaseDomain { 27 28 private static final long serialVersionUID = 1L; 29 30 private Integer id; 31 32 private String name; 33 34 private ClassUO classUO; 35 36 @Id 37 @GeneratedValue(strategy = GenerationType.AUTO) 38 public Integer getId() { 39 return id; 40 } 41 42 public void setId(Integer id) { 43 this.id = id; 44 } 45 46 public String getName() { 47 return name; 48 } 49 50 public void setName(String name) { 51 this.name = name; 52 } 53 54 @ManyToOne(fetch = FetchType.LAZY) 55 @JoinColumn(name = "classid", nullable = false) 56 @Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE) 57 public ClassUO getClassUO() { 58 return classUO; 59 } 60 61 public void setClassUO(ClassUO classUO) { 62 this.classUO = classUO; 63 } 64 65 public StudentUM() { 66 super(); 67 } 68 69 public StudentUM(String name, ClassUO classUO) { 70 super(); 71 this.name = name; 72 this.classUO = classUO; 73 } 74 75 }
此处类注解使用@Proxy(lazy = true),表示延迟检索指定对象。从测试类中可以看到,第22行输出“延迟加载:1”,表示执行正常,而在第23行打印那么时却报错了:org.hibernate.LazyInitializationException: could not initialize proxy - no Session。这个异常很简单,由于是延迟加载,studentUM只是一个代理类的实例而已,这个实例只初始化了标识符属性,其他属性都是null,当调用其他属性时才会执行真正的查询语句,但此时session已经关闭,无法执行执行查询,所以才会报错no Session。
1 package com.bao.sample.retrieve.strategy.umto; 2 3 import org.junit.Test; 4 import org.springframework.context.ApplicationContext; 5 import org.unitils.UnitilsJUnit4; 6 import org.unitils.spring.annotation.SpringApplicationContext; 7 8 import com.bao.sample.retrieve.strategy.umto.StudentUM; 9 import com.bao.sample.retrieve.strategy.umto.StudentUMService; 10 11 public class StudentUMServiceTest extends UnitilsJUnit4 { 12 13 @SpringApplicationContext( { "applicationContext.xml" }) 14 private ApplicationContext applicationContext; 15 16 @Test 17 public void loadStudent() { 18 StudentUMService studentUMService = (StudentUMService) applicationContext 19 .getBean("studentUMService"); 20 StudentUM studentUM = studentUMService.loadById(1); 21 22 System.out.println("延迟加载:" + studentUM.getId()); 23 System.out.println("报错:" + studentUM.getName()); 24 25 } 26 27 }
如果将该注解@Proxy(lazy = true)删除,或改为@Proxy(lazy = false),再次执行测试方法,便可以看到如下输出:
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 报错:jack
先前报错的地方,已经有正确的信息“jack”输出了。在此之前也已经执行了查询语句。
@Proxy仅对load()方法有效,false表示立即检索;默认为true,表示延迟检索.此时不会执行select语句,仅返回代理类的实例.
以上就是在类上加Proxy注解对于session.load()方法的区别,而session.get()方法没有这个限制,get方法在类级别永远都是立即加载检索的,而load方法在类级别上默认是延迟加载的。
2012-08-29 00:43:04 听雨轩