[TOC]
# Hibernate优化方案
## HQL优化
1.使用参数绑定
1.使用绑定参数的原因是让数据库一次解析SQL,对后续的重复请求可以使用用生成好的执行计划,这样做节省CPU时间和内存。
2.避免SQL注入
2.尽量少使用NOT
如果where子句中包含not关键字,那么执行时该字段的索引失效。
3.尽量使用where来替换having
Having在检索出所有记录后才对结果集进行过滤,这个处理需要一定的开销,而where子句限制记录的数目,能减少这方面的开销
4.减少对表的查询
在含有子查询的HQL中,尽量减少对表的查询,降低开销
5.使用表的别名
当在HQL语句中连接多个表时,使用别名,提高程序阅读性,并把别名前缀与每个列上,这样一来,可以减少解析时间并减少列歧义引起的语法错误。
6.实体的更新与删除
在hibernate3以后支持hql的update与delete操作
![](https://box.kancloud.cn/2ccdd52768678700659d5b4799c502b1_622x149.png)
### 一级缓存优化
一级缓存也叫做session缓存,在一个hibernate session有效,这级缓存的可干预性不强,大多于hibernate自动管理,但它提供清除缓存的方法,这在大批量增加(更新)操作是有效果的,例如,同时增加十万条记录,按常规进行,很可能会出现异常,这时可能需要手动清除一级缓存,session.evict以及session.clear.
## 检索策略(抓取策略)
### 延迟加载
延迟加载 是hibernate为提高程序执行的效率而提供的一种机制,即只有真正使用该对象的数据时才会创建。
load方法采用的策略延迟加载.
get方法采用的策略立即加载。
检索策略分为两种:
1. 1. 类级别检索
2. 2. 关联级别检索
### 类级别检索
类级别检索是通过session直接检索某一类对应的数据,例如
Customer c=session.load(Customer.class,1)
Session.createQuery(“from Order”)
类级别检索策略分为立即检索与延迟检索,默认是延迟检索,类级别的检索策略可以通过<class>元素的lazy属性来设置 ,默认值是true
在hbm配置文件中设置
![](https://box.kancloud.cn/cec421db919307765a6ed2a60badb07b_769x365.png)
### 关联级别检索
查询到某个对象,获得其关联的对象或属性,这种称为关联级别检索,例如
c.getOrders().size()
c.getName()
对于关联级别检索我们就要研究其检索策略(抓取策略)
### 抓取策略介绍
指的是查找到某个对象后,通过这个对象去查询关联对象的信息时的一种策略。
一对一 `<one-to-one>`
一对多(多对一) `<set>`下有`<one-to-many> <many-to-one>`
多对多` <set>`下有`<many-to- many>`
我们主要是在`<set>`与`<many-to-one>`或`<one-to-one>`上设置fetch lazy
例如:查询一个客户,要关联查询它的订单
客户是一的一方,在客户中有set集合来描述其订单,在配置中我们是使用
~~~
<set>
<one-to-many>
</set>..
~~~
可以在set标签上设置两个属性 fetch lazy
Fetch主要描述的是SQL语句的格式(例如是多条,子查询,多表联查
Lazy 控制SQL语句何时发送
例如:在查询一个订单时,要查询客户信息
`<many-to-one> 或<one-to-one>`
也可以设置fetch lazy
Fetch主要描述的是SQL语句的格式(例如是多条,子查询,多表联查
Lazy 控制SQL语句何时发送
总结:
讲解抓取策略
在两方面设置
~~~
<set fetch="" lazy="">
<many-to-one fetch="" lazy="">
<one-to-one>
~~~
### 注解配置抓取策略
问题:如何使用注解来设置
在`<setse>`设置的fetch与lazy可以使用下面注解来描述
![](https://box.kancloud.cn/b8f44c2f72d6d99c9ae1321da072d372_784x399.png)
## set上的fetch与lazy
set上的fetch与lazy它主要是用于设置关联的集合信息的抓取策略。
Fetch可取值有:
1. SELECT 多条简单的sql (默认值)
2. JOIN 采用迫切左外连接
3. SUBSELECT 将生成子查询的SQL
lazy可取值有:
1. TURE 延迟检索 (默认值)
2. FALSE 立即检索
3. EXTRA 加强延迟检索(及其懒惰)
![](https://box.kancloud.cn/413eef459a416dd2230b127ff5677f12_669x446.png)
### 第一种组合
![](https://box.kancloud.cn/741b5add6353648510577a5315bfe4da_649x129.png)
### 第二种组合
![](https://box.kancloud.cn/02463fefb17cf7d818a8ced374054728_694x146.png)
### 第三种组合
![](https://box.kancloud.cn/b68481f990b125995e633dd2b798e834_656x104.png)
当查询客户信息时,不会查询订单信息,当需要订单的个数时,也不会查询订单信息,
只会通过count来统计订单个数。
当我们使用size(),contains()或isEmpty()方法时不会查询订单信息。
### 第四种组合
如果fetch选择的是join方案,那么lazy它会失效。
生成SQl将采用的是迫切左外连接(left outer join fetch)
会立即查询。
![](https://box.kancloud.cn/0e851f39fea9105511537111b142494a_646x91.png)
### 第5种组合
![](https://box.kancloud.cn/2702dedd58e40fa26471c600e60915e9_647x96.png)
会生成子查询,但是我们在查询订单时采用的是延迟加载。
### 第6种组合
![](https://box.kancloud.cn/0896c30ad66ce082d012bd5b2b173ef7_659x90.png)
会生成子查询,在查询客户信息时,就会将订单信息也查询出来
### 第七种组合
![](https://box.kancloud.cn/02b9c631f96036f4ca942f21ebe7fe42_648x95.png)
在查询订单时,只会根据情况来确定是否要订单信息,如果不需要,例如我们
程序中size操作,那么就会发出`select count(*) from Order where c_customer_id=?`
### 结论
![](https://box.kancloud.cn/0ca1929b06516a751566df0363b21239_481x226.png)
![](https://box.kancloud.cn/6f78ac5511273b246ebc0004f2d6dacd_570x50.png)
no-session问题解决?
扩大session作用范围
![](https://box.kancloud.cn/a92f261ac8ca1ff40a40581ed5251e2a_568x335.png)
## One的一言fetch与lazy
`<set fetch lazy>`它主要是设置在获取到一的一方时,如果去查询多的一方。
在`<many-to-one>或<one-to-one>`如果去查询对方。
对于程序 就是在多的一方如何查询一的主方信息
例如:获取到一个订单对象,要查询客户信息。
Fetch可取值:
select 默认值,代表发送一条或多条简单的select语句
join 发送一条迫切左外连接
lazy可取值
false 不采用延迟加载
proxy 默认值 是否采用延迟,需要另一方的类级别延迟策略来决定
no-proxy 不用研究
![](https://box.kancloud.cn/1d42ed4829d0dc7876d79f87904c1872_667x399.png)
### 第一种组合
![](https://box.kancloud.cn/6a3134439a29f0bfa4da3c6344a442f0_439x195.png)
当我们执行时,会首先发送一条sql只查询订单信息,客户信息会延迟,只有真正需要客户信息时,才会发送sql来查询客户信息.
### 第二种组合
![](https://box.kancloud.cn/bd82d518110cc4eebff60ff46e6677b1_802x287.png)
### 第三种组合
![](https://box.kancloud.cn/88ea439f4eecbe86fd4f1396610d5598_566x137.png)
### 第四种组合
![](https://box.kancloud.cn/54c5ed43015293adb72eec86639a81ae_470x167.png)
## 批量抓取
我们在查询多个对象的关联对象时,可以采用批量抓取方式来对程序进行优化.
要想实现批量抓取:
可以在配置文件中 batch-size属性来设置
可以使用注解 @BatchSize(size=4)
可以采用批量抓取来解决N+1问题.
抓取客户的时候一次抓取几个联系人
查询客户,查询订单
![](https://box.kancloud.cn/a0284718ef3f03a323261d94be5ff644_734x473.png)
查询订单,查询客户
![](https://box.kancloud.cn/314c268f0d00612124b88eac92ab5428_769x578.png)
![](https://box.kancloud.cn/387acc86cd87c7a2a99a5d238e4d2944_815x370.png)
- 基础
- 编译和安装
- scanner类(键盘录入)
- Random类(随机数)
- 数组
- 方法
- 类
- ArrayList集合
- char与int
- eclipse
- IDEA
- 变量与常量
- 常用API
- String,StringBuffer,StringBuilder
- 正则,Date,DateFormat,Calendar
- 包装类,System,Math,Arrays,BigInteger,BigDecimal
- 集合,迭代器,增强for,泛型
- List,set,判断集合唯一
- map,Entry,HashMap,Collections
- 异常
- IO
- File
- 递归
- 字节流
- 字符流
- IO流分类
- 转换流
- 缓冲流
- 流的操作规律
- properties
- 序列化流与反序列化流
- 打印流
- commons-IO
- IO流总结
- 多线程
- 线程池
- 线程安全
- 线程同步
- 死锁
- lock接口
- ThreadLoad
- 等待唤醒机制
- 线程状态
- jdbc
- DBUtils
- 连接池DBCP
- c3p0连接池
- 网络编程
- 多线程socket上传图片
- 反射
- xml
- 设计模式
- 装饰器模式
- web service
- tomcat
- Servlet
- response
- request
- session和cookie
- JSP
- EL
- JSTL
- 事务
- 监听器Listener
- 过滤器Filter
- json
- linux安装软件
- 反射详解
- 类加载器和注解
- 动态代理
- jedis
- Hibernate
- 简介
- 创建映射文件
- Hibernate核心配置文件
- 事务和增删改查
- HibernateUtils
- 持久化对象的三种状态
- 检索方式
- query
- Criteria
- SQLQuery
- 持久化类
- 主键生成策略
- 缓存
- 事务管理
- 关系映射
- 注解
- 优化
- struts2
- 搭建
- 配置详解
- Action
- 结果跳转方式
- 访问ServletAPI方式
- 如何获得参数
- OGNL表达式
- valueStack 值栈
- Interceptor拦截器
- spring
- 导包
- IOC和DI
- Bean获取与实例化
- Bean属性注入
- spring注解
- 注解分层
- junit整合
- aop
- 动态代理实现
- cglib代理实现
- aop名词
- spring的aop
- aop-xml详解
- aop-注解详解
- 代理方式选择
- jdbcTemplate
- spring事务管理
- 回滚注意
- 事务传播属性
- MyBatis
- MyBatis简介
- 入门程序
- 与jdbc hibernate不同
- 原始Dao开发
- Mapper动态代理方式
- SqlMapConfig.xml配置文件
- 输入参数pojo包装类
- resultMap
- 动态sql
- 一对一关联
- 一对多
- 整合spring
- 逆向工程
- maven
- maven简介
- 仓库
- maven目录结构
- maven常用命令
- 生命周期
- eclipse中maven插件
- 入门程序
- 整合struct
- 依赖范围
- 添加插件
- idea配置
- jar包冲突
- 分模块开发
- 构建可执行的jar包(包含依赖jar包)
- springMVC
- 处理流程
- java面试
- java版本升级
- java1-8版本变更
- java9新特性
- 锁
- java资料
- idea
- jdk版本切换
- log4j
- 入门实例
- 基本使用方法
- Web中使用Log4j
- spring中使用log4j
- java代码优化