`

hibernate 懒加载及查询的部分知识

 
阅读更多

1.实体类:

Customer类如下:

Java代码 复制代码 收藏代码
  1. package com.reiyen.hibernate.domain;   
  2.   
  3. public class Customer {   
  4.   
  5.     private int id;   
  6.     private String name;   
  7.     private String email;   
  8.       //setter和getter方法   
  9. }  
package com.reiyen.hibernate.domain;

public class Customer {

	private int id;
	private String name;
	private String email;
      //setter和getter方法
}

 2.Customer.hbm.xml映射文件如下:

Xml代码 复制代码 收藏代码
  1. <hibernate-mapping package="com.reiyen.hibernate.domain">  
  2.     <class name="Customer">  
  3.         <id name="id">  
  4.             <generator class="native" />  
  5.         </id>  
  6.         <property name="name" />  
  7.         <property name="email" />  
  8.     </class>  
  9. </hibernate-mapping>  
<hibernate-mapping package="com.reiyen.hibernate.domain">
	<class name="Customer">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name" />
		<property name="email" />
	</class>
</hibernate-mapping>

 3.测试类如下:

Java代码 复制代码 收藏代码
  1. public class CustomerTest {   
  2.   
  3.     public static void main(String[] args) {   
  4.         add();   
  5.         Customer customer = getCustomer(1);   
  6.         System.out.println(customer.getName());   
  7.     }   
  8.     static void add(){   
  9.         Session session = null;   
  10.         Transaction tran = null;   
  11.         try {   
  12.             Customer customer = new Customer();   
  13.             customer.setName("xxlong");   
  14.             customer.setEmail("email@163.com");   
  15.             session = HibernateUtil.getSession();   
  16.             tran = session.beginTransaction();   
  17.             session.save(customer);   
  18.             tran.commit();   
  19.         } finally {   
  20.             if (session != null)   
  21.                 session.close();   
  22.         }   
  23.     }   
  24.     static Customer getCustomer(Integer id){   
  25.         Session session = null;   
  26.         try {   
  27.             session = HibernateUtil.getSession();   
  28.             Customer customer = (Customer)session.load(Customer.class, id);   
  29.             //System.out.println(customer.getClass()); //1   
  30.                        //customer.getName();//2   
  31.                        //Hibernate.initialize(customer); //3   
  32.             return customer;   
  33.         } finally {   
  34.             if (session != null)   
  35.                 session.close();   
  36.         }   
  37.     }   
  38. }  
public class CustomerTest {

	public static void main(String[] args) {
		add();
		Customer customer = getCustomer(1);
		System.out.println(customer.getName());
	}
	static void add(){
		Session session = null;
		Transaction tran = null;
		try {
			Customer customer = new Customer();
			customer.setName("xxlong");
			customer.setEmail("email@163.com");
			session = HibernateUtil.getSession();
			tran = session.beginTransaction();
			session.save(customer);
			tran.commit();
		} finally {
			if (session != null)
				session.close();
		}
	}
	static Customer getCustomer(Integer id){
		Session session = null;
		try {
			session = HibernateUtil.getSession();
			Customer customer = (Customer)session.load(Customer.class, id);
			//System.out.println(customer.getClass()); //1
                       //customer.getName();//2
                       //Hibernate.initialize(customer); //3
			return customer;
		} finally {
			if (session != null)
				session.close();
		}
	}
}

 运行此程序会抛出如下异常:

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

将注释为1的语句的注释去掉,运行可以发现load方法得到的customer对象如下所示:

class com.reiyen.hibernate.domain.Customer$$EnhancerByCGLIB$$c3543d5f

说明load得到的对象不是我们的实体类了,其实它是hibernate实现的Customer的一个子类,是Customer的一个代理类,此代理类在hibernate的Session没有关闭时能访问数据库,但一旦Session关闭,它就不能再访问数据库了。解决此异常的方法:即在Session关闭之前强迫此代理类去访问数据库。

如在程序中增加注释为2的程序即可。但写这样一句程序没有意义,所以在正式开发环境中一般增加注释为3的程序语句来解决此异常。

使用load方法获取对象时,它不会立即去访问数据库,它直接就实例化了一个此对象的代理对象返回给你,只有等到你真正需要使用此对象时,它才会去访问数据库。所以load方法在一定程度上能提高性能。注意:使用load方法时,永远不能使用if(customer != null)这种判断方法来判断load方法成功没有,因为它永远会返回给你一个代理对象。

懒加载是通过asm.jar和cglib.jar来实现的。

 

懒加载总结:

hibernate中懒加载是通过asm和cglib二个包实现的,
hibernate中要实现懒加载功能,你的实体类必须设计成非final的。
hibernate中懒加载的分类以及实现条件:
1.session.load懒加载
2.one-to-one(元素)懒加载:必须同时满足下面的三个条件时才能实现懒加载:1).lazy!=false 2).constrained=true 3).fetch=select
(因为主表不能有constrained=true,所以主表没有懒加载功能)\
3.one-to-many(元素)懒加载:1).lazy!=false 2).fetch=select
4.many-to-one(元素)懒加载:1).lazy!=false 2).fetch=select
5.many-to-many(元素)懒加载:1).lazy!=false 2).fetch=select
6.能够懒加载的对象都是被改写过的代理对象,当相关联的session没有关闭时,访问这些懒加载对象(代理对象)的属性(getId和getClass除外)时,hibernate会初始化这些代理,或用Hibernate.initialize(proxy)来初始化代理对象;
当相关联的session关闭后,再访问懒加载的对象将会出现异常。

 

4.根据ID查询区别:

Java代码 复制代码 收藏代码
  1. Query q = session.createQuery("from Customer where id=:id");   
  2.     q.setParameter("id",id);   
  3.     Customer customer = q.uniqueResult();  
		Query q = session.createQuery("from Customer where id=:id");
			q.setParameter("id",id);
			Customer customer = q.uniqueResult();

 与

Java代码 复制代码 收藏代码
  1. Customer customer = (Customer)session.load(Customer.class, id);   
  2. //Customer customer = (Customer)session.get(Customer.class, id);  
Customer customer = (Customer)session.load(Customer.class, id);
//Customer customer = (Customer)session.get(Customer.class, id);

 的区别是:后者能利用Hibernate的缓存,所以相对前者来说查询效率会高些(因为Query默认是直接去数据库中查询数据的)。

5。DetachedCriteri可在session外创建(在其他层创建,如Service中创建),然后用getExecutableCriteria(session)方法创建Criteria对象来完成查询。

在持久层定义方法dcQuery如下:

Java代码 复制代码 收藏代码
  1. public List<Customer> dcQuery(DetachedCriteria dCriteria){   
  2.         Session session = HibernateUtil.getSession();   
  3.         Criteria c = dCriteria.getExecutableCriteria(session);   
  4.         List<Customer> list = c.list();   
  5.         session.close();   
  6.         return list;   
  7.     }  
public List<Customer> dcQuery(DetachedCriteria dCriteria){
		Session session = HibernateUtil.getSession();
		Criteria c = dCriteria.getExecutableCriteria(session);
		List<Customer> list = c.list();
		session.close();
		return list;
	}

 在应用层使用dcQuery方法,如下:

Java代码 复制代码 收藏代码
  1. String name = request.getParameter("name");   
  2. String name = request.getParameter("email");   
  3.             DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);   
  4.             if (name != null && !name.isEmpty())   
  5.                 dc.add(Restrictions.ilike("name", name));   
  6.             if (email != null && !email.isEmpty())   
  7.                 dc.add(Restrictions.eq("email", email));   
  8.             List<Customer> customers = dcQuery(dc);  
String name = request.getParameter("name");
String name = request.getParameter("email");
			DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
			if (name != null && !name.isEmpty())
				dc.add(Restrictions.ilike("name", name));
			if (email != null && !email.isEmpty())
				dc.add(Restrictions.eq("email", email));
			List<Customer> customers = dcQuery(dc);

  6。N+1查询问题分析:

1).用Query.iterate可能会有N+1次查询(使用iterate进行查询时,它首先只是将查询的实体对象的id值查询出来,然后再根据id来查询实体)

Java代码 复制代码 收藏代码
  1. Query q = session.createQuery("from User");   
  2. java.util.Iterator<User> users = q.iterate();   
  3. while(users.hasNext()){   
  4.     System.out.println(users.next().getName());   
  5. }  
Query q = session.createQuery("from User");
java.util.Iterator<User> users = q.iterate();
while(users.hasNext()){
	System.out.println(users.next().getName());
}

 控制台打印的第一条SQL语句如下所示:

Hibernate:select user0.id as col_0_0_ from user user0_

说明它第一步只是将查询对象的id查询出来.然后它根据id再一个一个的将所有要查询实体查询出来,此过程如下:

首先根据id在一级缓存中查找,如果没有找到,再到二级缓存中去找(如果配置了二级缓存的话),如果在二级缓存中还没有找到,则再去数据库中查询.如果缓存中有要查询的对象,则iterate是很高效的,因为它只去数据库中查询了一次;但如果缓存中没有要查询的数据,则iterate查询效率是非常低的,因为它会产生N+1次查询!
2).懒加载时获取关联对象可能有N+1次查询
3).如果打开查询的缓存即使用list也可能有N+1次查询

分享到:
评论

相关推荐

    懒加载异常解决.docx

    ### 懒加载异常解决知识点 #### 一、懒加载技术概述 懒加载(Lazy Loading)是一种按需加载策略,在程序设计中广泛应用于减少内存占用和提高系统性能。在Java开发中,尤其针对数据库操作频繁的应用场景,如...

    Hibernate懒加载之&lt;class&gt;标签上的lazy

    Hibernate懒加载(Lazy Loading)是一种优化策略,其核心思想是在真正需要使用对象的属性时才去加载它们,而不是在初始化对象时一次性加载所有数据。这有助于减少不必要的数据库交互,提高系统性能。 在Hibernate中...

    hibernate学习资料大全

    以上只是压缩包中部分可能包含的知识点,实际学习资料可能包括教程文档、示例代码、实战项目等,通过深入学习和实践,开发者可以全面掌握Hibernate的精髓,并将其应用到实际开发中,提高开发效率,降低维护成本。...

    Hibernate Hibernate5 讲义 PDF

    Hibernate的懒加载、缓存策略以及事务管理等高级特性,使得它能高效地与关系型数据库进行交互,满足现代应用程序对数据持久化的需求。 北京动力节点教育培训公司提供的Hibernate5讲义,不仅对Hibernate框架进行了...

    Hibernate面试题专栏 - 最全的Hibernate面试题, Hibernate笔试题, Hibernate问题

    - 使用懒加载(LazyInitializationException)和立即加载(Eager Loading)控制数据加载时机。 以上只是Hibernate众多知识点的一部分,实际面试中可能涉及更多细节,如级联操作、事务隔离级别、延迟加载机制、乐观...

    当设置lazy=true时,怎样使用extjs和Hibernate

    在IT行业中,ExtJS是一个广泛使用的JavaScript库,用于构建富...通过理解这些知识点,开发者可以有效地在使用Hibernate懒加载特性的后端与ExtJS前端之间构建高效的通信,实现数据的按需加载,优化应用程序的性能。

    Hibernate 框架

    5. **懒加载和级联操作**:懒加载允许延迟加载关联的对象,以提高性能。级联操作则可以将对一个对象的操作自动应用到与其关联的对象上。 6. **缓存机制**:Hibernate支持一级缓存(Session级别的缓存)和二级缓存...

    hibernATE的源代码

    - **懒加载和即时加载**:理解Hibernate如何通过代理对象实现数据的延迟加载,以及何时触发数据加载。 - **关联映射**:一对一、一对多、多对一和多对多关系的映射实现。 - **事件和监听器**:观察Hibernate的生命...

    Hibernate基础学习源码

    通过@OneToMany、@ManyToOne注解,以及@JoinColumn和@JoinTable的使用,学习如何在实体间建立关联,实现数据的级联操作和懒加载。 5. **Hibernate_M2M**: 最后一部分重点在于多对多(Many-to-Many)关系的映射,这...

    Hibernate入门(代码+笔记)

    这包括懒加载(Lazy Loading)策略,通过延迟加载提高性能;级联操作(Cascade)可以将父对象的操作同步到子对象;以及开放 session 在视图(Open Session In View,OSIV)模式,确保在Web请求生命周期内保持一个...

    Hibernate4.1.11中文手册

    这包括了主键生成策略、属性类型映射、关联关系(一对一、一对多、多对一、多对多)的配置,以及懒加载(Lazy Loading)和级联操作(Cascading)等高级特性。 在事务处理部分,手册会阐述Hibernate的事务管理机制,...

    hibernate笔记.txt

    3. **懒加载和级联操作**:Hibernate支持懒加载策略,即只有在真正需要数据时才会从数据库加载,这对于提高应用性能和减少资源消耗非常重要。此外,Hibernate还支持级联操作,允许在一个操作中自动触发其他相关的...

    hibernate4.2.4-jar包

    11. **懒加载(Lazy Loading)**:Hibernate 支持懒加载机制,即关联对象只有在真正需要时才加载,这有助于减少内存占用和提高性能。 12. **级联操作(Cascading)**:当对一个实体进行操作(如保存、删除)时,...

    Hibernate学习心得

    实践中,我们可能会遇到懒加载、级联操作、缓存机制、一对一、一对多、多对多等关系映射的配置问题,以及性能优化等方面的挑战。 最后,`Struts+Hibernate整合.txt`提到了Struts,这是一个经典的MVC框架。Struts与...

    Hibernate实战第2版.zip

    8. Advanced Topics:深入探讨高级主题,如懒加载(Lazy Loading)、集合的优化、批量操作、级联操作、子查询、联合查询、多态性处理、JPA(Java Persistence API)对比和整合等。 9. 性能优化:讲解如何通过调整...

    hibernate商品分页展示

    4. **懒加载**:对于关联的对象,可以采用懒加载策略,避免一次性加载过多数据。 总结,hibernate商品分页展示涉及到的主要知识点有分页逻辑、Hibernate的Criteria查询、分页参数的计算以及查询结果的处理。通过...

    Hibernate逍遥游记 .pdf

    - 使用懒加载来减少一次查询中的数据加载量。 - 通过批量操作和批处理更新来提高处理大量数据的效率。 通过以上知识点的掌握,读者可以更加深入地了解Hibernate,熟练使用Hibernate 3.3版本进行Java对象持久化开发...

    HIbernate PPT

    3. **3持久化对象的状态和加载.ppt**:详细解释了Hibernate中对象的生命周期,以及对象的瞬时态、持久态和脱管态,还包括对象的加载机制,如懒加载和立即加载。 4. **4实体映射策略.ppt**:探讨了不同的映射策略,...

    Hibernate数据库操作实例.zip

    7. **延迟加载和立即加载**:理解Hibernate的懒加载机制,以及何时使用立即加载。 8. **事务管理**:了解Hibernate的Transaction API,如何在代码中控制事务的开始、提交、回滚。 9. **Spring与Hibernate集成**:...

    深入浅出Hibernate(含源码)

    12. **懒加载与立即加载**:Hibernate提供了懒加载机制,可延迟加载关联对象,以避免数据冗余和性能问题。立即加载则会在需要时立即获取关联对象。 13. **实体状态与生命周期**:Hibernate识别四种实体状态:瞬时、...

Global site tag (gtag.js) - Google Analytics