- 浏览: 440383 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (162)
- easymock (3)
- 模板引擎 (3)
- JForum (4)
- web (9)
- spring (10)
- java (20)
- struts (9)
- uml (3)
- java pattern (19)
- JQuery (14)
- 多线程 (13)
- database (21)
- PS (3)
- ejb (6)
- 版本管理 svn , maven , ant (2)
- protocol (1)
- 测试 (1)
- ws (7)
- Apache (4)
- 脚本语言 (1)
- guice (1)
- 分布式 (4)
- 架构 (0)
- 经验 (1)
- 版本管理 svn (1)
- maven (1)
- ant (1)
- 书籍 (1)
- Linux (1)
最新评论
-
Master-Gao:
稍微明白了点,,有点萌萌哒
为什么匿名内部类参数必须为final类型 -
waw0931:
终于明白了,谢谢!
为什么匿名内部类参数必须为final类型 -
十三圆桌骑士:
提供了两个链接还是有用的。
安装Mondrian -
放方芳:
[flash=200,200][/flash]
Freemarker标签使用 -
放方芳:
[b][/b]
Freemarker标签使用
首先是第一个误区:延迟加载只能作用于关联实体
看到这个是不是在想:非关联实体延迟加载有什么用?
为了解答上面这个问题,我们可以先考虑另一个问题:Hibernate Session的get和load方法有什么区别?
如果你的回答是:当方法参数为数据库不存在的id时,get会返回null,load会抛出异常 ,那么恭喜你,进入了第二个误区
如果此时你还想补充一下:load会从缓存中取出数据而get不会 ,再次恭喜,进入第三个误区
如果你在上面三个误区中有一个踏入了,那么我敢打赌,你一定是被网上那些半吊子的工程师们写的博客给戕害了。。。。
此时是不是很愤怒?这些长久以来你牢记在心的Hibernate的特性原来都是浮云。。。。
呵呵,接下来我们一个个来走出这些误区。
Mop上无图无真相,我们这里无码无真相——不要误会,我是说代码
首先看看第二个误区:当方法参数为数据库不存在的id时,get会返回null,load会抛出异常
如果你现在想说:没错啊,我自己就测试过,get确实返回了null,load确实抛出了异常。
那么请回答:load是在执行load语句时抛出异常的吗?为什么?如果你答不上来,那么接着看下面的代码吧:
@Test(expected = IllegalArgumentException.class)
public void 延迟加载() throws Exception {
// 启动
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = (User)session.load(User.class, 100L); // 不存在的ID
try {
user.getName();
} catch (ObjectNotFoundException ex) {
// 命中数据库发现没有对象即抛出ObjectNotFoundException异常
throw new IllegalArgumentException("随便抛出一个不可能的异常");
}
tx.commit();
session.close();
}
由这个test case我们可以知道load并不是在执行时就马上抛出不存在数据的异常的(ObjectNotFoundException),这是为什么呢?再看代码:
@Test(expected = IllegalArgumentException.class)
public void 延迟加载() throws Exception {
// 启动
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = (User)session.load(User.class, 100L); // 不存在的ID
Assert.assertTrue(user instanceof HibernateProxy);
user.getId(); // 由于ID是不被延迟加载的属性,因此不会抛出异常
try {
Hibernate.initialize(user); // 此时才会触发命中数据库
//user.getName();
} catch (ObjectNotFoundException ex) {
// 命中数据库发现没有对象即抛出ObjectNotFoundException异常
throw new IllegalArgumentException("随便抛出一个不可能的异常");
}
tx.commit();
session.close();
}
看高亮的几行,代码已经把问题说得很清楚了,get和load最大的区别是(假设缓存皆空的情况):get是立即命中数据库去查询这条记录,而load则是直接返回一个代理对象(HibernateProxy)而不命中数据库,换句话来说load是为单个对象进行了延迟加载,如果你不去访问这个对象的除ID外的属性,即使目标记录不存在它也永远都不会抛出异常。 由于load不立即命中数据库,它确实有一定几率提高效率
OK,我想上面一段话应该可以解释第一和第二个误区了,那么第三个误区呢?
再看代码
@Test
public void get和load一级缓存测试() throws Exception {
// 启动
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
// 验证load在缓存为空的情况下是否会使得加载的对象过一级缓存
User user1 = (User)session.load(User.class, 1L); // 存在的ID,此时虽然没有解开Proxy但已经进入缓存
Assert.assertTrue(user1 instanceof HibernateProxy);
Hibernate.initialize(user1); // 解开Proxy,会触发命中数据库操作
User user3 = (User)session.get(User.class, 1L);
Assert.assertTrue(user3 instanceof HibernateProxy); // 即使使用get,但由于缓存中存储的是一个Proxy,所以这里得到的也是Proxy
Hibernate.initialize(user3); // 解开Proxy,但不会命中数据库
// 验证在load一个不存在的ID后,不解开然后get
User user4 = (User)session.load(User.class, 100L); // 不存在的ID,仍然将Proxy进入缓存
Assert.assertTrue(user4 instanceof HibernateProxy);
//Hibernate.initialize(user3); // 不解开Proxy
try {
session.get(User.class, 100L); // 得到Proxy,命中数据库尝试解开Proxy,由于ID不存在因此抛出异常
Assert.fail("ID不存在所以会出错,不会执行本条");
} catch (ObjectNotFoundException ex) {
}
// 清空缓存
session.clear();
// 验证缓存为空的情况下get是否为Proxy
User user6 = (User)session.get(User.class, 1L); // 命中数据库,直接将组装完成的User实体进入缓存
Assert.assertTrue(!(user6 instanceof HibernateProxy));
// 验证get从缓存中取出对象
User user7 = (User)session.get(User.class, 1L);
Assert.assertTrue(!(user7 instanceof HibernateProxy)); // 缓存中是真实的User对象,get取出的就是真实的User对象
// 验证load是否从一级缓存取数据
User user8 = (User)session.load(User.class, 1L);
Assert.assertTrue(!(user8 instanceof HibernateProxy)); // 缓存中是真实的User对象,load取出的也是真实的User对象
tx.commit();
session.close();
}
相信注释已经足够详细了,打开hibernate.show_sql,总共命中三次数据库(执行SQL),分别在高亮的三行处,其余的全是从缓存中取数据。
而且值得注意的一点是,如果对象是从load加载到缓存中的,那么不论get还是load获取出来的都是一个Proxy,如果没有被解开过,那么get会尝试解开它;如果对象是从get加载到缓存中的,那么load和get取出来都会是真实的实体对象。也就是说,get和load都会从缓存中取出对象,且取出的对象总是保持其第一次加载时的状态(load为Proxy,get为真实对象)
以上代码是一级缓存的验证,想验证二级缓存只需要从Hibernate中开启二级缓存再次运行代码即可
发表评论
-
安装Mondrian
2014-04-11 10:48 4618Mondrian and OLAP Mondrian i ... -
NoSql 笔记
2014-02-18 17:39 738看了一些关于NoSql的文 ... -
mysql explain用法
2014-02-14 11:53 913补充一点: id 就是 sql 语句中 select 出现 ... -
数据库范式概念解析(第一范式,第二范式,第三范式)
2013-02-26 10:17 1096大部分数据库从业人员 ... -
ORACLE数据库基础知识
2013-02-23 11:39 852http://wenku.baidu.com/view/958 ... -
Oracle 的性能优化概述
2013-02-23 11:34 1040Oracle 的性能优化概 ... -
mysql 索引
2013-02-23 11:33 943索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一 ... -
hibernate规则
2012-12-18 14:58 1081实体类的编写规则 l 实体类必须具备无参 ... -
Hibernate 关联关系映射(Association Relationship Mapping)
2012-12-17 18:55 949一对一主键关联 数据表为:夫妻表 POJO 为 ... -
关系型数据库性能优化总结(转)
2012-06-13 14:17 824关系型数据库性能优化 ... -
spring+hibernate架构中Dao访问数据库的几种方法
2011-11-28 18:10 1396spring+hibernate架构中Dao访问数据库的几种方 ... -
mybatis 缓存(二)
2011-10-20 13:05 5333缓存不适合情况:select ... -
mybatis 缓存(一)
2011-10-20 11:27 1251缓存概述 http://www.iteye.com/topi ... -
mybatis 基本
2011-10-20 11:14 1449今天刚听说iBATIS改名为MyBatis,实际上就是iBAT ... -
mybatis 多对多 处理
2011-09-26 18:41 42025下面的例子让新手看 ... -
MyBatis+Spring基于接口编程的原理分析
2011-09-17 15:57 3414整合Spring3及MyBatis3 对于整合Sprin ... -
解释 关闭statement 和rs
2010-09-19 13:14 2317很多朋友在Java开发中, ... -
HIBERNATE
2010-07-30 11:51 859使用java进行项目开发也有不少年头了,应用从网站到金融产品到 ... -
Oracle嵌套表和数组的使用(省去了连接查询)
2010-07-27 17:18 2267Oracle嵌套表的使用 1. 创建对象类型 create ... -
延迟加载
2010-07-11 14:04 1314could not initialize proxy - no ...
相关推荐
Hibernate延迟加载以及利用Spring 大家看看 参考一下
hibernate延迟加载解决 延迟加载的具体解决方法
详细介绍hibernate延迟加载,对hibernate初学者有一定的帮助
Hibernae 的延迟加载是一个非常常用的技术,实体的集合属性默认会被延迟加载,实体所关联的实体默认也会被延迟加载。Hibernate 通过这种延迟加载来降低系统的内存开销,从而保证 Hibernate 的运行性能。
深入理解hibernate懒加载技术,正确使用懒加载
Hibernate延迟加载机制.zip
Hibernate延迟加载Hibernate延迟加载
hibernate延迟加载技术详细解 ,http://www.che2.com/提供
Hibernate延迟加载介绍.doc
Hibernate 延迟加载
关于hibernate延迟加载,有很好的参考价值
Hibernate集合属性的延迟加载.doc
Hibernate的延迟加载
Hibernate在查询某个对象时,立即查询与之关联的对象: 1、当select的语句数目太多,需要频繁的访问数据库,会影响查询的性能。 2、在应用程序只需要访问要的对象,而不需要访问与他关联的对象的场景下,加载与之...
介绍几种解决Flex 与 Hibernate 的延迟加载问题。我在实际项目中使用的是Gilead。
主要介绍了Hibernate延迟加载技术,结合实例形式详细分析了Hibernate延迟加载所涉及的各种常用技巧,需要的朋友可以参考下