hql懒加载后判断对象是否存在_hibernate 懒加载及查询的部分知识

1.实体类:

Customer类如下:

Java代码  

packagecom.reiyen.hibernate.domain;

publicclassCustomer {

privateintid;

privateString name;

privateString email;

//setter和getter方法

}

package com.reiyen.hibernate.domain;

public class Customer {

private int id;

private String name;

private String email;

//setter和getter方法

}

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

Xml代码  

3.测试类如下:

Java代码  

publicclassCustomerTest {

publicstaticvoidmain(String[] args) {

add();

Customer customer = getCustomer(1);

System.out.println(customer.getName());

}

staticvoidadd(){

Session session =null;

Transaction tran =null;

try{

Customer customer =newCustomer();

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();

}

}

staticCustomer 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

returncustomer;

}finally{

if(session !=null)

session.close();

}

}

}

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代码  

Query q = session.createQuery("from Customer where id=:id");

q.setParameter("id",id);

Customer customer = q.uniqueResult();

Query q = session.createQuery("from Customer where id=:id");

q.setParameter("id",id);

Customer customer = q.uniqueResult();

Java代码  

Customer customer = (Customer)session.load(Customer.class, id);

//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代码  

publicList dcQuery(DetachedCriteria dCriteria){

Session session = HibernateUtil.getSession();

Criteria c = dCriteria.getExecutableCriteria(session);

List list = c.list();

session.close();

returnlist;

}

public List dcQuery(DetachedCriteria dCriteria){

Session session = HibernateUtil.getSession();

Criteria c = dCriteria.getExecutableCriteria(session);

List list = c.list();

session.close();

return list;

}

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

Java代码  

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 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 customers = dcQuery(dc);

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

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

Java代码  

Query q = session.createQuery("from User");

java.util.Iterator users = q.iterate();

while(users.hasNext()){

System.out.println(users.next().getName());

}

Query q = session.createQuery("from User");

java.util.Iterator 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次查询

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值