【Hibernate】Hibernate的检索策略:lazy、fetch
来源:互联网 发布:执业药师网络报名机构 编辑:程序博客网 时间:2024/05/18 02:10
检索策略
延迟检索延迟Session.load()
——Session.get()/Query.list()都会立即检索关联级别立即检索
延迟检索
迫切左外连接检索延迟Session.load()/get()
Query(注意,Query会忽略xml中配置的迫切左外连接策略)
Criteria
三种检索策略
- 不管对象处于持久化状态、游离状态,都可以从一个对象导航到与他关联的另一个对象
- select语句数目多;
- 可能加载程序不需要访问的对象,浪费内存
- 类级别
- 程序需要立即访问的对象
- 使用了二级缓存
- 由应用程序决定需要加载哪些对象
- 避免立即检索的缺点
- 如果要访问游离状态的代理类实例,则必须保证其在持久化状态时已经被初始化
- 一对多、多对多关联时
- 程序不需要立即访问的对象
左外连接
- 不管对象处于持久化状态、游离状态,都可以从一个对象导航到与他关联的另一个对象
- select语句数目少
- 复杂的表连接会影响性能;
- 可能加载程序不需要访问的对象,浪费内存
- 多对一、一对一关联
- 程序需要立即访问的对象
- 数据库系统具有良好的表连接性能
- true:延迟检索(default)
- false:立即检索
- true:延迟检索(default)
- extra:增强延迟检索
- false:立即检索
- proxy:延迟检索
- no-proxy:无代理延迟检索
- false:立即检索
- 无此属性
- select:select查询语句(default)
- subselect:带子查询的select语句
- join:迫切左外连接检索
- select:select查询语句
- join:迫切左外连接检索
——fetch配置为join时,会覆盖lazy配置
类级别的检索策略
立即检索
配置为立即检索时,执行session.load()时会立即查询数据库,返回BO。——如果查不到则返回null。
session.get()、query.list()总是会进行立即检索。
延迟检索
配置为延迟检索时,执行session.load()时并不立即查询数据库,不执行select,仅返回BO的一个代理类实例:
- 这个代理类扩展自BO类,由Hibernate在运行时使用CGLIB工具动态产生;
- 代理类实例仅初始化OID属性,其他属性都是null
- 第一次访问BO属性(非ID属性)时,Hibernate会执行select+初始化代理类实例
——若select查不到,则抛ObjectNotFoundException
——getId()并不能触发查询。
问题:
若session关闭后,才去访问游离状态的BO的属性,会抛出LazyInitializationException
Transaction tx = session.biginTransaction();Customer customer = (Customer)session.load(Customer.class, new Long(1));...order.setCustomer(customer);tx.commit();session.close();customer.getName();//LazyInitializationException
解决:
Hibernate.initialize()可在session范围内显式初始化代理类实例:
Transaction tx = session.biginTransaction();Customer customer = (Customer)session.load(Customer.class, new Long(1));...order.setCustomer(customer);//显式初始化代理类实例if(!Hibernate.isInitialized(customer)){ Hibernate.initialize(customer);}tx.commit();session.close();customer.getName();//OK
一对多、多对多关联的检索策略
<set name="orders" inverse="true" lazy = "true" fetch = "select"> <key column="CUSTOMER_ID"/> <one-to-many class="com.Order"/></set>
参考表2、表3
select * from ORDERS where CUSTOMER_ID in (1,2,3);ANYsubselect通过subselect语句来初始化集合属性:
select * from ORDERS where CUSTOMER_ID in (select ID from CUSTOMERS)ANYjoin采用迫切左外连接检索策略;此时lazy的取值会被忽略
select * from CUSTOMERS left outer join ORDERS
on CUSTOMER.ID = ORDERS.CUSTOMER_ID
where CUSTOMERS.ID = 1;
与类级别不同:不管是否延迟加载,都会返回代理类:org.hibernate.collections.PersistentSet
lazy=true延迟加载时:
返回的PersistentSet中的元素为空。
调用customer.getOders()并不能触发select,只有当调用其iterator、size、isEmpty、contains方法时才会执行数据库查询。
lazy=extra增强延迟加载时:
调用size、isEmpty、contains时也不能触发select,只有当调用iterator时才执行数据库查询。
batch-size属性
例如如下场景:
//先查询出4个customer。//-------其order属性为代理类实例,即此时session缓存中有4个未初始化的order集合代理类实例List list = session.createQuery("from Customer").list();...//再分别查询其orderscustomer1.getOrders().iterator();//1customer2.getOrders().iterator();//2customer3.getOrders().iterator();//3customer4.getOrders().iterator();//4
若不配置batch-size,则SQL如下:
select * from ORDERS where CUSTOMER_ID=1; //1select * from ORDERS where CUSTOMER_ID=2; //2select * from ORDERS where CUSTOMER_ID=3; //3select * from ORDERS where CUSTOMER_ID=4; //4
而若配置batch-size=3,则SQL优化为:
select * from ORDERS where CUSTOMER_ID in (1,2,3); //1select * from ORDERS where CUSTOMER_ID=4; //4
- 执行代码行1时,查询order集合,由于session缓存中共有4个oders集合代理类实例未被初始化,所以执行in (1,2,3)批量初始化
- 执行代码行2时,无需再初始化其orders集合代理类,所以就无需再查数据库
- 执行代码行3时,无需再初始化其orders集合代理类,所以就无需再查数据库
- 执行代码行4时,本应再批量初始化3个orders集合代理类实例,但是session缓存中不足3个代理类实例,所以仅初始化剩余的实例。
——作用:减少了查询语句数目。
fetch=select与subselect的区别:
subselect时,batch-size的设置就无意义了。因为上例代码会转换为如下SQL:
select * from ORDERS where CUSTOMER_ID in (select ID from CUSTOMERS); --代码中查询Customer的语句
fetch=join:
query.list()会忽略join设置。默认为延迟加载、select
多对一、一对一关联的检索策略
参考表2,lazy取值可为proxy、no-proxy、false
与一对多不同,将true分为proxy、no-proxy两种情况
lazy=proxy
//1.查询Order: select * from ORDER where id=1;// 此时order.customer属性时Customer代理类实例Order order = (Order)session.get(Order.class, new Long(1));//2.返回Customer代理类实例Customer customer = order.getCustomer();//3.初始化Customer代理类实例String name = customer.getName();
lazy=no-proxy
//1.查询Order: select * from ORDER where id=1;// 此时order.customer属性=null,----并非代理类实例!!Order order = (Order)session.get(Order.class, new Long(1));//2.查询数据库CustomerCustomer customer = order.getCustomer();//3.String name = customer.getName();
lazy=false
//1.查询Order: select * from ORDER where id=1// 并且查其Customer:select * from CUSTOMER where id=1;// 随之查询Customer属性:select * from ORDERS where CUSTOMER_ID=1Order order = (Order)session.get(Order.class, new Long(1));//2.Customer customer = order.getCustomer();//3.String name = customer.getName();
fetch=join
//1.查询Order及其Customer// select * from ORDERS left outer join CUSTOMERS// on ORDERS.CUSTOMER_ID = CUSTOMER.ID // where ORDERS.ID=1;// 若Customer.hbm.xml中lazy=false,则同时还查ORDERS:// select * from ORDERS where CUSTOMER_ID=1 Order order = (Order)session.get(Order.class, new Long(1));//2.Customer customer = order.getCustomer();//3.String name = customer.getName();
join的深度
注意上面这个例子,fetch=join,查Order时会对Customer进行左连接;
假如Customer又和表A左连接、表A又和表B左连接,那查询Order岂不要连接多个表?
hibernate考虑了这个问题,默认情况下hibernate.max_fetch_depth=2
- 【Hibernate】Hibernate的检索策略:lazy、fetch
- Hibernate】Hibernate的检索策略:lazy、fetch
- Hibernate 检索策略 lazy fetch batch-size
- hibernate的抓取策略(fetch和lazy)
- Hibernate 检索策略 (lazy,batch-size,fetch属性)
- hibernate的 lazy 和 fetch
- Hibernate学习之检索策略(lazy,fetch,batch-size等)
- Hibernate的lazy策略
- 浅谈hibernate lazy fetch
- hibernate lazy和fetch
- HIbernate lazy fetch
- hibernate的 lazy 和 fetch 如何配置
- Hibernate fetch lazy cascade 的解释
- hibernate的 lazy 和 fetch 一般配置
- hibernate 中lazy、banth 、fetch的对比
- Hibernate的检索策略
- Hibernate的检索策略
- Hibernate的检索策略
- 吃土豆
- java 把url传参的汉字变成%百分号形式,<c:url><c:param>,url提交汉字乱码
- 当你对未来迷茫的时候,请打开这个锦囊!
- 单链表的逆置
- 杂记--随时更新
- 【Hibernate】Hibernate的检索策略:lazy、fetch
- 黑马程序员_面试题之交通灯
- Struts2开发步骤
- 动态代理代码实现实例
- gethostbyname(),gethostbyaddr()的使用
- Android Project Butter分析
- 第三章代码及其结果
- php 分页
- 创业总结:创业公司怎样留人