Hibernate缓存和懒加载的坑你知道多少?这5个简单问题回答不上来就不敢说会用hibernate
问题1:session.flush()调用之后,懒加载还生效吗?
如果不生效,那是抛异常还是没有任何反应,或者直接返回null?
答案:生效。可以理解为在同一个session当中,懒加载只会执行一次。
问题2: 多次调用实体类的导航属性,是否会多次进行sql查询?
如果session.flush()调用之后呢?
答案:不会进行多次sql查询,即使是在session.flush之后。
问题3:新创建的某个实体类对象,当调用session.flush()之后,能否直接加载其导航属性?
比如下方的代码,能否直接从数据库获取到ID为roleId的Role对象呢?
User user = new User(......); user.setRoleId(roleId); db.save(user); db.getSession().flush(); Role role = user.getRole();
答案:不能。
问题4:多次调用session.get(Serializable id) 是否会每次都从数据库查询?
答案:否,不仅仅是从缓存里面读取,而且每次返回的竟然是同一个对象!注意,是同一个内存地址哦!
问题5:你知道ID相同的实体类(加了@Entity注解)每次返回的是同一个内存对象吗?
上图一共执行了3次sql,这个比较好理解,难以理解的是:居然上面3个employee是引用的同一个内存地址,也就是说是完完全全一模一样的同一个对象!比如我把employee1的名字改了,那么employee2的名字也就改了,真TM surprising!
既然上图里面的三个employee是同一个对象,那我们可以猜测那是因为Employee类加了@Entity注解,而这个注解会改变hashcode的值。如果查询返回一个DTO对象,是不是就应该是不同的对象了吧?马上就来验证这个猜测,看下图:
上图说明:猜对了。
上图说明:即使第2个employee是从数据库查出来的,但是由于它跟第一个employee是同一个内存对象,所以它的name属性已经被改成了内存中的那个name值了。神奇吧!
hibernate懒加载天坑:对于ManyToOne注解居然默认是FetchType.EAGER
EAGER是什么意思呢?比如User类有个role属性, 当加载user对象的时候,就会同时加载role对象,也就是你期望的只有一条简单sql从user表查询,但是却执行了两条sql(或者是join查询)。
所以,通常情况下对于ManyToOne注解,都需要手工设置fetch = FetchType.LAZY,否则会出现严重性能问题。
本文中的测试来自jframe 框架
基于spring mvc搭建的多层级多模块java web应用程序框架。包含:基础设施层、数据库定义规范、数据库访问规范、日志记录规范、多层级异常捕获、标准ajax规范、母版页规范、视图呈现规范、JavaScript框架规范等。实际上该框架定义的规范极其详细,比如数据库定义层:枚举类使用规范、datetime/bool/string字段规范、1对1、1对多、多对1、多对多外键关系映射规范、父类定义规范、字段注释规范、懒加载规范等等。。。
技术交流QQ群:651499479,欢迎java大神指点迷津,也欢迎新手进群学习。
github地址: https://github.com/leotsai/jframe
THE END.