Java 常见的面试题(Hibernate)
一、为什么要使用 hibernate?
- 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
- hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作
- hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
- hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。
二、什么是 ORM 框架?
**ORM:**对象关系型映射,主要是解决对象与关系数据库存在的互不匹配的现象的技术
ORM的方法论基于3个核心原则
- 简单:以最基本的形式建模数据
- 传达型:数据库结构被任何人都能理解的语言文档化
- 精确性:基于数据模型创建正确标准化了的结构
常用的ORM框架有:hibernate,mybatis
三、hibernate 中如何在控制台查看打印的 sql 语句?
在application.properties配置如下代码:
- spring.jpa.properties.hibernate.show_sql=true//控制台是否打印
- spring.jpa.properties.hibernate.format_sql=true//格式化sql语句
- spring.jpa.properties.hibernate.use_sql_comments=true//指出是什么操作生成了该语句
四、hibernate 有几种查询方式?
HQL查询、SQL查询、QBC条件查询
HQL的具体分类
- 属性查询
- 参数查询、命名参数查询
- 关联查询
- 分页查询
- 统计函数。
HQL和SQL的区别:HQL是面向对象查询操作的,SQL是结构化查询语言 是面向数据库表结构的
五、hibernate 实体类可以被定义为 final 吗?
可以将Hibernate的实体类定义为final类,但这种做法并不好。
因为Hibernate会使用代理模式在延迟关联的情况下提高性能,如果你把实体类定义成final类之后,因为 Java不允许对final类进行扩展,所以Hibernate就无法再使用代理了,如此一来就限制了使用可以提升性能的手段。不过,如果你的持久化类实现了一个接口而且在该接口中声明了所有定义于实体类中的所有public的方法轮到话,你就能够避免出现前面所说的不利后果。
六、在 hibernate 中使用 Integer 和 int 做映射有什么区别?
在Hibernate中,如果将OID定义为Integer类型,那么Hibernate就可以根据其值是否为null而判断一个对象是否是临时的,如果将OID定义为了int类型,还需要在hbm映射文件中设置其unsaved-value属性为0。
七、hibernate 是如何工作的?
- 通过Configuration config = new Configuration().configure();//读取并解析hibernate.cfg.xml配置文件
- 由hibernate.cfg.xml中的读取并解析映射信息
- 通过SessionFactory sf = config.buildSessionFactory();//创建SessionFactory
- Session session = sf.openSession();//打开Sesssion
- Transaction tx = session.beginTransaction();//创建并启动事务Transation
- persistent operate操作数据,持久化操作
- tx.commit();//提交事务
- 关闭Session
- 关闭SesstionFactory
八、get()和 load()的区别?
- 如果未能发现符合条件的记录,Hibernate get方法返回null,而load方法会抛出一个ObjectNotFoundException。
- load方法可返回没有加载实体数据的代 理类实例,而get方法永远返回有实体数据的对象。
总之对于get和load的根本区别,一句话,hibernate对于 load方法认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,如果在使用过程中发现了问题,只能抛异常;而对于get方 法,hibernate一定要获取到真实的数据,否则返回null。
九、说一下 hibernate 的缓存机制?
**Hibernate缓存的作用:**Hibernate是一个持久层框架,经常访问物理数据库,为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据
**Hibernate缓存分类:**Hibernate一级缓存和Hibernate二级缓存
- Hibernate一级缓存又称为“Session的缓存”,它是内置的,意思就是说,只要你使用hibernate就必须使用session缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。在第一级缓存中,持久化类的每个实例都具有唯一的OID。
- Hibernate二级缓存又称为“SessionFactory的缓存”,由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。第二级缓存是可选的,是一个可配置的插件,在默认情况下,SessionFactory不会启用这个插件。
什么样的数据适合存放到第二级缓存中:
- 很少被修改的数据
- 不是很重要的数据,允许出现偶尔并发的数据
- 不会被并发访问的数据
- 常量数据
不适合存放到第二级缓存的数据:
- 经常被修改的数据
- 绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发
- 与其他应用共享的数据。
**Hibernate查找对象如何应用缓存:**当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;如果都查不到,再查询数据库,把结果按照ID放入到缓存
删除、更新、增加数据的时候,同时更新缓存
**Hibernate管理缓存实例:**无论何时,我们在管理Hibernate缓存(Managing the caches)时,当你给save()、update()或saveOrUpdate()方法传递一个对象时,或使用load()、 get()、list()、iterate() 或scroll()方法获得一个对象时, 该对象都将被加入到Session的内部缓存中。当随后flush()方法被调用时,对象的状态会和数据库取得同步。 如果你不希望此同步操作发生,或者你正处理大量对象、需要对有效管理内存时,你可以调用evict() 方法,从一级缓存中去掉这些对象及其集合。
十、hibernate 对象有哪些状态?
hibernate里对象有三种状态:
- Transient 瞬时 :对象刚new出来,还没设id,设了其他值。
- Persistent 持久:调用了save()、saveOrUpdate(),就变成Persistent,有id
- Detached 脱管 : 当session close()完之后,变成Detached。
十一、在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?
获取openSession和CurrentSession:
session=HibernateSessionFactory.getSession();
session=HibernateSessionFactory.getSessionFactory().getCurrentSession();
1、getCurrentSession()与openSession()的区别?
- 采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession()创建的session则不会
- 采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession()创建的session必须手动关
2、使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置
* 如果使用的是本地事务(jdbc事务)
<property name="hibernate.current_session_context_class">thread</property>
* 如果使用的是全局事务(jta事务)
<property name="hibernate.current_session_context_class">jta</property>
十二、hibernate 实体类必须要有无参构造函数吗?为什么?
是的,必须要有无参的构造方法;
原因:Hibernate框架会调用这个默认构造方法来构造实例对象,即Class类的newInstance方法 ,这个方法就是通过调用默认构造方法来创建实例对象的 。
当查询的时候返回的实体类是一个对象实例,是Hibernate动态通过反射生成的。反射的Class.forName(“className”).newInstance()需要对应的类提供一个无参构造方法,必须有个无参的构造方法将对象创建出来,单从Hibernate的角度讲 他是通过反射创建实体对象的 所以没有默认构造方法是不行的,另外Hibernate也可以通过有参的构造方法创建对象。
注:以上内容仅提供参考和交流,请勿用于商业用途,如有侵权联系本人删除!
注:此博客只是为了记忆相关知识点,大部分为网络上的文章,在此向各个文章的作者表示感谢!