• 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.

  • 相关阅读:
    javaIO流--Writer,Reader
    javaIO操作之字节输入流--InputStream
    javaIO操作之字节输出流--OutputStream
    java中IO操作
    java中的方法引用
    java中lamda表达式的应用
    java8接口定义增强
    java中的强大的枚举(基本没人用)
    java中的泛型
    详述 IntelliJ IDEA 远程调试 Tomcat 的方法
  • 原文地址:https://www.cnblogs.com/leotsai/p/five-questions-about-hibernate-cache-and-lazy-load.html
Copyright © 2020-2023  润新知