疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Hibernate的检索策略


 

 
1.区分立即检索和延迟检索
 
@Test
public  void testLazyTrueOrFalse(){
  Session session=sf.openSession();
  Transaction tx=session.beginTransaction();
  Customer c=(Customer)session.load(Customer.class, 1); //lazy=false:这个位置产生select语句
  System.out.println("xxxxxxxxxxxxxxxxx");
  c.getAge();   //lazy=true 这个位置产生select语句
  tx.commit();
  session.close();
}
* <class name="cn.itcast.search.Customer" table="customers" lazy="true">
class元素的lazy=true:为延迟检索,默认值
 
class元素的lazy=false:为立即检索
 
* get方法永远是立即检索
2.理解延迟检索中的代理
 
@Test
public  void testLazyTrueProxy(){
  Session session=sf.openSession();
  Transaction tx=session.beginTransaction();
  Customer c=(Customer)session.load(Customer.class, 1);//不产生select语句
  System.out.println(c.getClass());   //不产生select语句
  System.out.println(c.getId());     //不产生select语句
  System.out.println(c.getName());   //产生select语句
  tx.commit();
  session.close();
}
* 只有延迟检索才会产生代理对象
* hibernate会为产生的代理对象分配一个OID,但其他的属性不分配值,此时还没有查询
 
* hibernate使用javassist-3.9.0.GA.jar包创建代理
 
3.初始化延迟检索中的代理
 
@Test
public  void initProxy(){
  Session session=sf.openSession();
  Transaction tx=session.beginTransaction();
  Customer c=(Customer)session.load(Customer.class, 1);//不产生select语句
  System.out.println(c.getClass());   //不产生select语句
  System.out.println(c.getId());     //不产生select语句
  System.out.println(Hibernate.isInitialized(c));
  //如果代理对象没有被初始化
  if(!Hibernate.isInitialized(c)){
  //初始化代理对象  产生select语句
  Hibernate.initialize(c);
      }
  tx.commit();
  session.close();
}
* Hibernate.isInitialized(c) 判断代理对象是否被初始化 对集合对象也适用
* Hibernate.initialize(c); 初始化代理对象 hibernate执行select查询
4.区分类级别和关联级别的检索
 
* 类级别的检索:
Customer c=(Customer)session.load(Customer.class, 1);
session的方法直接检索Customer对象,对Customer对象到底采用立即检索还是延迟检索方式
通过class元素的lazy属性设定
 
* 关联级别的检索:
Customer c=(Customer)session.load(Customer.class, 1);
Set set=c.getOrders()//检索Order对象的set集合
在这个例子中
session.load(Customer.class, 1):查询的主体表
c.getOrders():查询客体表
查询客体表是否发生,以何种方式发生(立即检索、延迟检索和迫切左外连接检索),就是关联级别检索
通过set元素lazy属性设定
@Test
public  void testLazyTrueProxy2(){
  Session session=sf.openSession();
  Transaction tx=session.beginTransaction();
  Query query=session.createQuery("from Customer");
  List<Customer> list=query.list();  //select
  for(Customer c:list){
  System.out.println(c.getId()+"   "+c.getName());
  }
  tx.commit();
  session.close();
}
* 不管lazy的值为true还是false,query.list()方法总是立即检索
5.类级别检索策略
* 如果程序加载一个对象的目的是为了访问它的属性, 可以采取立即检索. 如果程序加载一个持久化对象的目的是仅仅为了获得它的引用, 可以采用延迟检索
* 无论 <class> 元素的 lazy 属性是 true 还是 false, Session 的 get() 方法及 Query 的 list() 方法在类级别总是使用立即检索策略
 
* 若 <class> 元素的 lazy 属性为 true 或取默认值, Session 的 load() 方法不会执行查询数据表的 SELECT 语句, 仅返回代理类对象的实例, 该代理类实例有如下特征:
由 Hibernate 在运行时采用 javassist 工具动态生成
Hibernate 创建代理类实例时, 仅初始化其 OID 属性
在应用程序第一次访问代理类实例的非 OID 属性时, Hibernate 会初始化代理类实例
 
6.关联级别的检索策略
 
* 在映射文件中, 用 <set> 元素来配置一对多关联及多对多关联关系. <set> 元素有 lazy 和 fetch 属性
 
@Test
public  void testSetFetchLazy(){
  Session session=sf.openSession();
  Transaction tx=session.beginTransaction();
  Customer c=(Customer)session.get(Customer.class, 1);
  Set<Order> orderes=c.getOrderes();
  orderes.size();
  Iterator<Order> it=orderes.iterator();
  while(it.hasNext()){
  Order o=it.next();
  System.out.println(o.getId()+"  "+o.getOrderNumber());
  }
  tx.commit();
  session.close();
}
* <set name="orderes" table="orders" inverse="true" fetch="join" lazy="false">
fetch="join" lazy="false" 采用迫切左外连接查询 一条sql语句
 
fetch="join" lazy="true" 采用迫切左外连接查询 一条sql语句
 
fetch="join" lazy="extra" 采用迫切左外连接查询 一条sql语句
 
fetch="select" lazy="false" 采用立即检索 两条sql语句 先查询客户,再通过客户id查询订单
 
fetch="select" lazy="true" 采用延迟检索 两条sql语句 先查询客户,再通过客户id查询订单
 
fetch="select" lazy="extra" 采用延迟检索 极其懒惰 上面的例子中只会查询orders集合的大小 两条sql语句 先查询客户,再通过客户id查询订单
 
fetch="subselect" lazy="false" 采用立即检索 两条sql语句 先查询客户,再通过客户id查询订单
 
fetch="subselect" lazy="true" 采用延迟检索 两条sql语句 先查询客户,再通过客户id查询订单
 
fetch="subselect" lazy="extra" 采用延迟检索 极其懒惰 上面的例子中只会查询orders集合的大小 两条sql语句 先查询客户,再通过客户id查询订单
 
* 上面subselect不会出现子查询,因为客户只查询了一个,而子查询中的in语句是存放多个的,这里没有子查询的语句出现
@Test
public  void QuerySetFetchLazy(){
  Session session=sf.openSession();
  Transaction tx=session.beginTransaction();
  Query query=session.createQuery("from Customer c");
  List<Customer> list=query.list();
  list.get(0).getOrderes().size();
  tx.commit();
  session.close();
}
<set name="orderes" table="orders" inverse="true" fetch="join" lazy="false">
 
fetch="join" lazy="false" 立即检索客户关联到订单集合 4条sql语句 一条查询客户 3条查询客户对应的订单
 
fetch="join" lazy="true" 延迟检索客户关联到订单集合 4条sql语句 一条查询客户 3条查询客户对应的订单
 
fetch="join" lazy="extra" 增强延迟检索客户关联到订单集合(要什么查什么) 4条sql语句 一条查询客户 3条查询客户对应的订单集合的大小
 
fetch="select" lazy="false" 立即检索客户关联到订单集合 4条sql语句 一条查询客户 3条查询客户对应的订单
 
fetch="select" lazy="true" 延迟检索客户关联到订单集合 4条sql语句 一条查询客户 3条查询客户对应的订单
 
fetch="select" lazy="extra" 增强延迟检索客户关联到订单集合(要什么查什么)4条sql语句 一条查询客户 3条查询客户对应的订单集合的大小
 
fetch="subselect" lazy="false" 采用立即检索 两条sql语句 先查询客户,再通过子查询查询订单
 
fetch="subselect" lazy="true" 采用延迟检索 两条sql语句 先查询客户,再通过子查询查询订单
 
fetch="subselect" lazy="extra" 采用延迟检索 极其懒惰 两条sql语句 先查询客户,再通过子查询查询订单集合的大小
 
* 因为查出来是Customer对象集合,所以不会迫切左外连接查询 如果语句改为这样Query query=session.createQuery("from Customer c where c.id=1"); 就是迫切左外连接查询
 
* 在延迟检索(lazy 属性值为 true) 集合属性时, Hibernate 在以下情况下初始化集合代理类实例
应用程序第一次访问集合属性: iterator(), size(), isEmpty(), contains() 等方法
通过 Hibernate.initialize() 静态方法显式初始化
* 增强延迟检索(lazy 属性为 extra): 与 lazy=“true” 类似. 主要区别是增强延迟检索策略能进一步延迟 Customer 对象的 orders 集合代理实例的初始化时机:
当程序第一次访问 orders 属性的 iterator() 方法时, 会导致 orders 集合代理类实例的初始化
当程序第一次访问 order 属性的 size(), contains() 和 isEmpty() 方法时, Hibernate 不会初始化 orders 集合类的实例, 仅通过特定的 select 语句查询必要的信息, 不会检索所 有的 Order 对象
 
7.多对一和一对一关联的检索策略
* <many-to-one fetch="join" lazy="false">
 
fetch="join"
 
* 如果使用get方式检索, lazy="false/proxy/no-proxy"总是使用迫切左外连接检索
 
*如果使用query方式检索,
 
lazy="false ,这时不再采用切左外连接检索,而是采用立即检索 先查询订单,再通过订单的表的外键id查询客户 4条语句 先查订单 再查订单对应的客户
lazy="proxy,这时不再采用切左外连接检索,而是采用延迟检索 先查询订单,再通过订单的表的外键id查询客户 4条语句 先查订单 再查订单对应的客户
 
lazy="no-proxy",这时不再采用切左外连接检索,而是采用延迟检索 先查询订单,再通过订单的表的外键id查询客户 4条语句 先查订单 再查订单对应的客户 fetch=select
*lazy="false" 立即检索(先查询订单,在通过订单的外键查询客户)
 
*lazy="proxy"
 
* 对端的class元素中的lazy="false",立即检索
<class name="cn.itcast.search.Customer" table="customers" lazy="false">
* 对端的class元素中的lazy="true",延迟检索
<class name="cn.itcast.search.Customer" table="customers" lazy="true">
 
8.1组合1 many2one立即检索+set立即检索
 
输出如下语句
 
*select * from orders where id=?
 
*Select* from customers where id=?
 
*Select * from orders where customer_id=?
 
8.2组合2 many2one迫切左外+set立即检索
 
输出如下语句
 
*select * from orders o left outer joincustomers c on c.id=o.customer_idwhere o.id=?
 
*Select * from orders where customer_id=?
 
8.3组合3 many2one立即检索+set迫切左外
输出如下语句
 
*Select * from order where id=?
 
*select * from orders o left outer joincustomers c on c.id=o.customer_idwhere c.id=?
 
9.1批量检索 从一的一端查询 查询所有的客户
 
* <set> 元素有一个 batch-size 属性, 用来为延迟检索策略或立即检索策略设定批量检索的数量. 批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能. 默认值是
 
 <set name="orderes" table="orders"  inverse="true" fetch="select" lazy="true" batch-size="2">
9.2批量检索 从多的一端查询 查询所有的订单
<class name="cn.itcast.search.Customer" table="customers" lazy="true" batch-size="2">