为了进一步优化Hibernate的性能可以使用
延迟加载技术管理数据抓取策略进行缓存管理 等方面考虑来提高Hibernate的性能
延迟加载(load)
延迟加载(load)是Hibernate为提高程序执行效率而提供的一种机制即只有真正使用该对象的数据时才会创建
延迟加载的过程通过代理(Proxy)机制来实现延迟加载Hibernate从数据库获取某一个对象数据时获取某一个对象的集合属性值时或获取某一个对象所关联的另一个对象时由于没有使用该对象的数据(除标识符外)Hibernate并不从数据库加载真正的数据而只是为该对象创建一个代理对象来代表这个对象这个对象上的所有属性都为默认值只有在真正需要使用该对象的数据时才创建这个真正的对象真正从数据库中加载它的数据
当调用Session上的load()方法加载一个实体时当Session加载某个实体时会对这个实体中的集合属性值采用延迟加载当Session加载某个实体时会对这个实体所单端关联的另一个实体对象采用延迟加载
关闭延迟加载在加载单个实体时可以使用get()方法
对于实体中的集合属性可以在这个集合的(<set><bag><list>…)添加属性lazy=false单端关联另一个实体对象时可以在映射文件中配置<onetoone><manytoone> 添加属性lazy=false注意onetoone不能有constrained=true(产生的sql语句中显示外键)否则懒加载不起作用
Hibernate中默认采用延迟加载的情况主要有以下几种
? 当调用Session上的load()方法加载一个实体时会采用延迟加载
? 当Session加载某个实体时会对这个实体中的集合属性值采用延迟加载(onetomany)
? 当Session加载某个实体时会对这个实体所单端关联(onetoone manytoone)的另一个实体对象采用延迟加载
? 第二种和第三种的区别是第二种情况下取消延时加载的方法是在单方即有set属性的一方的映射文件的set标签后设置懒加载的属性lazy=false;第三种情况则是在多方即有manytoone的一方的映射文件中的manytoone标签后设置lazy=false
能够懒加载的对象都是被改写过的代理对象当相关联的session没有关闭时访问这些懒加载对象(代理对象)的属性(getId和getClass除外)hibernate会初始化这些代理或用Hibernateinitialize(proxy)来初始化代理对象当相关联的session关闭后再访问懒加载的对象将出现异常
抓取策略(fetch)
通过配置抓取策略来直接影响session的get()和load()方法的查询效果
单端关联<manytoone><oneto_one>上的抓取策略
可以给单端关联的映射元素添加fetch属性select:延迟加载 join:在同一条select语句使用内连接来获得对象的数据和它关联对象的数据此时关联对象的延迟加载失效
集合属性上的抓取策略
select:延迟加载join:在同一条select语句使用内连接来获得对方的关联集合此时关联集合上的lazy会失效subselect:另外发送一条查询语句或子查询抓取这个策略对HQL的查询也起作用
延迟加载案例分析
情况一单个实体调用load()方法取消懒加载
[java]
package comhbsitest;
import orghibernateSession;
import orgjunitTest;
import comhbsidomainUser;
import comhbsiutilsHibernateUtil;
publicclass TestLazy {
//测试get()方法get()方法不管你有没有用到总会执行sql语句
@Test
publicvoid testGet(){
Session session = HibernateUtilgetSession()
User user = (User) sessionget(Userclass)
// Systemoutprintln(usergetName())
HibernateUtilclose()
//这里要注意的是即使关闭了session使user处于托管状态仍然可以可以使用user对象这是因为虽然处于托管状态但是这个对象是存在属性值的对象并没有把他删除只是隔绝了它与数据库的打交道的通道
Systemoutprintln(usergetName())
}
//测试load()方法不执行sql语句用到的时候才执行
@Test
publicvoid testLoad(){
Session session = HibernateUtilgetSession()
User user = (User) sessionload(Userclass)
//这里输出id也不会执行sql语句直接从上面你传进去的id中获取id没有从数据库中查找所以也不执行sql语句
Systemoutprintln(usergetId())
//而输出name就不一样了这时其实就是实例化了代理对象这是的代理对象有了name的属性这时即使你关闭了session也可以通过这个对象获取到name;如果注释这句即不实例化代理对象又在关闭session后执行输出name属性这时会报错could not initialize proxy
// Systemoutprintln(usergetName())
HibernateUtilclose()
Systemoutprintln(usergetName())
}
}
情况二set集合上取消懒加载
//测试如果在映射文件中将集合属性中的懒加载设置为false后将连带着orders表中数据一块提出来即两条select语句
[java]
@Test
publicvoid find(){
Session session = HibernateUtilgetSession()
Customer cus = (Customer) sessionget(Customerclass)
Systemoutprintln(cusgetCname())
//用到下面这种方法输出会出现两天sql语句而且是分开的如果用到懒加载会出现先输出两条sql语句在输出结果
//这里不能直接方法链式输出cusgetOrd()getOname()因为cusgetOrd()返回的是一个set集合
Set<Orders> orders = cusgetOrd()
Systemerrprintln(orderssize())
HibernateUtilclose()
}
方法三<onetoone><manytoone> 取消懒加载
[java]
@Test
publicvoid find(){
//默认使用懒加载即用着一条sql语句就输出一条如果设置延时加载为false后输出两条sql语句将不需要的顾客信息也查出来
Session session = HibernateUtilgetSession()
Orders ord = (Orders) sessionget(Ordersclass)
Systemoutprintln(ordgetOname())
HibernateUtilclose()