2019年Java面试题(十六) Hibernate 2019-04-27

1. list,iterate区别

• 使用list()方法获取查询结果,每次发出一条查询语句,获取全部数据

• 使用iterate()方法获取查询结果,先发出一条SQL 语句用来查询满足条件数据的id,然后依次按这些id 查询记录,也就是要执行N+1 条SQL 语句(N 为符合条件的记录数)

• list()方法将不会在缓存中读取数据,它总是一次性的从数据库中直接查询所有符合条件的数据,同时将获取的数据写入缓存

• iterate()方法则是获取了符合条件的数据的id 后,首先根据id 在缓存中寻找符合条件的数据,若缓存中无符合条件的数据,再到数据库中查询

2. 如何优化Hibernate?

1).使用双向一对多关联,不使用单向一对多

2).灵活使用单向一对多关联

3).不用一对一,用多对一取代

4).配置对象缓存,不使用集合缓存

5).一对多集合使用Bag,多对多集合使用Set

6). 继承类使用显式多态

7). 表字段要少,表关联不要怕多,有二级缓存撑腰

3. Hibernate 核心接口session介绍

1、作用:提供基本的保存,删除,更新,和加载Java对象

2、什么是清理缓存:

Session能够在某些时间点,按照缓存中对象的变化来执行相关的SQL语句,来同步更新数据库,这一过程别称为清理缓存(flush)

3、SessionFactory是线程安全的(可以多个对象共用同一个对象)。而Session不是线程安全的。

为了解决Session线程不安全我们采用ThreadLocal方案。

ThreadLocal 模式的解决方案:

ThreadLocal并不是一个线程的本地实现,也就是说它不是一个Thread,而是Thread local variable(线程局部变量)。它的作用就是为每一个使用这个变量的线程提供一个变量的副本,并且每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。

ThreadLocal模式实例代码:

public void getSession() {

Configuration cfg = new Configuration().configure();

SessionFactory sf = cfg.buildSessionFactory();

session = sf.openSession();

}

//创建ThreadLocal对象

private static final ThreadLocal threadLodacl = new ThreadLocal();

public void getSession() {

Configuration cfg = new Configuration().configure();

SessionFactory sf = cfg.buildSessionFactory();

//session = sf.openSession();

//解决session线程非安全的方式

this.session = (Session) threadLodacl.get();

if(session == null){

this.session = sf.openSession();

threadLodacl.set(this.session);

}

}

4.获取session的两种方式介绍

1、 getCurrentSession创建的Session会绑定到当前线程,而openSession不会

2、 getCurrentSession创建的Session会在事务回滚或者事务提交后自动关闭,而openSession创建的必须手动关闭(调用Session的cloe()方法)

5. Hibernate操作的对象有三种状态

1、瞬时状态(Transient)/临时。2.、持久化状态(persistent)。3、托管状态(detached)/游离状态

1、当一个对象通过new 新创建的时候就是瞬时状态

    瞬时状态下对象的主键没有值,也没有纳入session的管理,数据库表中也没有对应的记录,当我们调用save等相关的其他方法是则进入了持久化状态,

2、持久化状态下对象纳入了session管理中,对象标示符有值。Hibernate保证在同一个session实例的缓存中数据库中的一条记录只对应唯一的一个持久化对象。session在清理缓存时会根据持久化对象的属性变化会同步更新数据库。当session关闭后持久化状态就会变成托管状态。当持久化对象调用delete方法就由持久化变成了移除状态

3、托管状态下的特点:对象不处于session的管理中。但他曾经与某个持久化上下文发生过关联(session),对象标示符有值,数据库可能存在与之相对的记录。Hibernate不能够保证托管状态下的数据和数据库中的数据同步更新。

4、临时和游离状态下的对象特点:等待垃圾回收,

6. Hibernate有哪几种查询数据的方式

      (1)导航对象图查询

      (2)OID查询

      (3)HQL

      (4)QBC

      (5)本地SQL

7. Hibernate优化

1、避免or操作

where 子句包含or 操作,执行时不使用索引

可以使用in条件来替换

2、避免使用not

where 子句包含not 关键字,执行时该字段的索引失效

使用比较运算符替换not

3、避免like的特殊形式

查询时,尽可能少使用like

4、避免having子句

尽可能在where 子句中指定条件

5、避免使用distinct

在不要求或允许冗余时,应避免使用distinct

8. 什么是懒加载 懒加载用什么技术实现,如何解决session关闭导致的懒加载问题 解决的方案有缺点吗

懒加载就是延迟加载,采用代理技术实现,采用openSessionInViewFilter,openSessionInViewFilter其实上就是一个过滤器页面打开时开启session,页面访问结束时关闭session

当访问用户过多,而且网速过慢的时候,会挤爆系统

事务扩大了 加锁导致资源等待时间过长

session范围变大  如果加载页面的时间过长 如网速比较慢  session内存时间过长 导致系统性能下载

数据库连接不能及时释放

9. hibernate核心类

congfigeration负责管理配置信息

sessionfactory负责创建出session

session负责调用持久化方法

Transaction 负责事务管理

query为查询接口

10. hibernate抓取策略

Hibernate的 抓取策略有四种

1、 join        连接抓取 它是通过select语句使用外连接来加载实体或者集合  懒加载会失效--同等于mybatis中的嵌套结果

2、 select    查询抓取 它是通过发送一条select语句抓取当前对象关联的实体或者集合 一条查自己 一条抓关联数据

3、 subselect  子查询抓取 发送一条select语句查询出关联的实体或者集合,然后通过子查询in完成

4、 batch-size  批量抓取

11. hibernate 的原理         

1. 读取并解析配置文件

2. 读取并解析映射信息,创建SessionFactory

3. 打开Sesssion

4. 创建事务Transation

5. 持久化操作

6. 提交事务

7. 关闭Session

8. 关闭SesstionFactory

12. Hibernate 的session.save()与session.saveOrUpdate()的区别?

1.save()方法,调用save 方法时,首先会在session 缓存中查找保存对象如果实体对象已经处于Persient 状态,直接返回;否则并将保存至数据库,对象变为持久状态。

2.saveOrUpdate()方法:和save 方法一样首先在session 缓存中查找,判断对象是否为为保存状态,如果对象处于Persient,不执行操作,处于Transient 执行save 操作,处于Detached 调用saveOrUpdate 将对象与session 重新关联(简单的说就是该方法会先看该对象是否已经存在,如果已经存在就更新,否则新增保存),如果此时saveOrUpdate 的对象与另一个与Session 关联的对象持有相同的持久化标识则抛出相同的标识符异常。

13. Hibernate 中sedssion.get()与session.load()的区别?

Session.load/get 方法均可以根据指定的实体类和id 从数据库读取记录,并返回与之对

应的实体对象。其区别在于:

1) 如果未能发现符合条件的记录, get 方法返回null , 而load 方法会抛出一个

ObjectNotFoundException。

2) load 支持延迟加载,get 不支持

3) load 方法可返回实体的代理类实例,而get 方法永远直接返回实体类。

4) load 方法可以充分利用内部缓存和二级缓存中的现有数据,get 方法则仅仅在内部缓存

中进行数据查找,如没有发现对应数据,将越过二级缓存,直接调用SQL 完成数据读取。

14. 介绍下hibernate

Hibernate 是一个开放源代码Java 语言下的对象关系映射解决方案。它为面向对象的领域模型到传统的关系型数据库的映射,提供了一个使用方便的框架。Hibernate 也是目前Java开发中最为流行的数据库持久层框架。将软件开发人员从大量相同的数据持久层相关编程工作中解放出来,Hibernate 不仅负责从Java 类到数据库表的映射(还包括从Java 数据类型到SQL 数据类型的映射),还提供了面向对象的数据查询检索机制,从而极大地缩短的手动处理SQL 和JDBC 上的开发时间。

15. Hibernate 中的HQL 和criteria 的区别?

1.QBC(Query by Criteria)查询对查询条件进行了面向对象封装,符合编程人员的思维方式;

2.HQL(Hibernate Query Language)查询提供了更加丰富的和灵活的查询特性,在涵盖

Criteria 查询的所有功能的前提下,提供了类似标准SQL 语句的查询方式,同时也

提供了更加面向对象的封装。

16. 介绍hibernate 延持加载属性

Hibernate 通过lazy 来指定加载策略,一般值为true 或false,。设为flase 表示立即加载,true 表过延迟加载。

17. 列举你接触过的框架,说明特点和原理

Hibernate 特点:

1. 基于JDBC 的主流持久化框架,是一个优秀的ORM 实现,对JDBC 访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。

2. hibernate 使用Java 反射机制,而不是字节码增强程序来实现透明性。

3. hibernate 的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。

Spring 特点:

Spring 框架的主要优势之一低侵入式的架构思想,实现了IOC 容器。另外一个AOP 的编程也在很多应用场合下地位较重。提供了对各种不同类型框架的支持,如:Web 容器、持入层、事务层、其它J2EE 组件等。

18. Ibatis 框架和Hibernate 框架各有什么特点?

19. 为什么要用ORM? 和JDBC 有何不一样?

orm 是一种思想,就是把object 对象转变成数据库中的记录,或者把数据库中的记录转变成object 对象,我们可以用jdbc 来实现这种思想,orm 的思想本质就是建立是JDBC 上,对JDBC 的一种封装,这种封装可以省去了直接使用jdbc 的繁琐细节,提高了开发效率,现在用的较多的ORM 工具很多,一般我们公司采用的ORM 框架主要有hibernate 和MyBatis。当然也听说一些其他orm 工具,如toplink,ojb 等。

20. 简述Hibernate 和JDBC 的优缺点?

1、封装了jdbc,简化了很多重复性代码。

2、简化了DAO 层编码工作,使开发更对象化了。

3、移植性好,支持各种数据库,如果换个数据库只要在配置文件中变换配置就可以了,不用改变hibernate 代码。

4、支持透明持久化,因为hibernate 操作的是纯粹的(pojo)java 类,没有实现任何接口,没有侵入性。

21. 写Hibernate 的一对多和多对一双向关联的orm 配置?

1、 配置一对多

2、 多对一

22. Hibernate 对象有几种状态?如何转换

共3 种状态,分别是:Transient 状态(瞬时)、Persient 状态(持久)、Detached(脱管状态)状态。

23. Hibernate 中有几种关系映射

主要有单向一对一、单向一对多、单向多对一、单向多对多、双向一对一、双向一对多、双向多对多

24. 谈谈Hibernate的理解,一级和二级缓存的作用,在项目中Hibernate都是怎么使用缓存的

一级缓存为session基本的缓存,是内置的不能卸载。一个Session做了一个查询操作,它会把这个结果放在一级缓存中,如果短时间内这个session又做了同一个操作,那么hibernate就直接从一级缓存中获取数据。

二级缓存是SessionFactory的缓存,分为内置缓存和外置缓存两类。即查询结果放在二级缓存中,如果同一个sessionFactory创建的某个session执行了相同的操作,hibernate就会从二级缓存中获取结果。适合放在二级缓存中的数据包括:很少被修改的数据,不是很重要的数据,允许出现偶偶并发的数据,不会被并发访问的数据,参考数据。不适合放在二级缓存中的数据:经常被修改的数据,财务数据,绝对不允许出现并发,与其他应用共享的数据。

25. Hibernate session的load()和get()的区别?

1:如果你使用load方法,hibernate认为该id对应的对象(数据库记录)在数据库中是一定存在的,所以它可以放心的使用,它可以放心的使用代理来延迟加载该对象。在用到对象中的其他属性数据时才查询数据库,但是万一数据库中不存在该记录,那没办法,只能抛异常,所说的load方法抛异常是指在使用该对象的数据时,数据库中不存在该数据时抛异常,而不是在创建这个对象时。由于session中的缓存对于hibernate来说是个相当廉价的资源,所以在load时会先查一下session缓存看看该id对应的对象是否存在,不存在则创建代理。所以如果你知道该id在数据库中一定有对应记录存在就可以使用load方法来实现延迟加载。 对于get方法,hibernate会确认一下该id对应的数据是否存在,首先在session缓存中查找,然后在二级缓存中查找,还没有就查数据库,数据库中没有就返回null(网上有很多误解以为get就马上去数据库查找根本不先查session那是不正确的,不想信你就去做下试验便知)。

2、“get()永远只返回实体类”,但实际上这是不正确的,get方法如果在session缓存中找到了该id对应的对象,如果刚好该对象前面是被代理过的,如被load方法使用过,或者被其他关联对象延迟加载过,那么返回的还是原先的代理对象,而不是实体类对象,如果该代理对象还没有加载实体数据(就是id以外的其他属性数据),那么它会查询二级缓存或者数据库来加载数据,但是返回的还是代理对象,只不过已经加载了实体数据。

3、再注重说明get方法首先查询session缓存,没有的话查询二级缓存,最后查询数据库;反而load方法创建时首先查询session缓存,没有就创建代理,实际使用数据时才查询二级缓存和数据库。

总之对于get和load的根本区别,一句话,hibernate对于load方法认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,如果在使用过程中发现了问题,只能抛异常;而对于get方法,hibernate一定要获取到真实的数据,否则返回null。

26. 各种关联关系下的lazy懒加载区别?

1、 one-to-one懒加载

一对一的懒加载并不常用,因为懒加载的目的是为了减少与数据库的交互,从而提高执行效率,而在一对一关系中,主表中的每一条数据只对应从表的一条数据库,就算都查询也不会增加多少交互的成本,而且主表不能有contrained=true,所以主表是不能懒加载的。但是从表可以有。实现此种懒加载必须在从对象这边同时满足三个条件:

a)lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)

b)Constrained = true ;

c)fetch=select。

注:当fetch设置为join时,懒加载就会失效。因为fetch的作用是抓取方式,他有两个值分别为select和join,默认值为select。即在设为join时,他会直接将从表信息以join方式查询到而不是再次使用select查询,这样导致了懒加载的失效。

2、 one-to-many懒加载

与one-to-one关联不同,对one-to-many而言,主表的每一条属性都会对应从表的多条数据,这个时候懒加载就显得非常有效了。比如一个部门里面有多个员工,如果没有懒加载,每查询这个部门的时候都会查询出多个员工,这会大大增加与数据库交互的成本。所以Hbernate默认的是加入懒加载的。这就是查询集合属性的时候返回的是一个PersistentIndexed*类型对象的原因。该对象其实就是一个代理对象。当然,可以在映射文件中通过将lazy属性设为假来禁用。

Hibernate默认对one-to-many就是使用的懒加载,但用户也可以取消懒加载操作:

一:设置lazy=”false”;

二:设置fetch=”join”.

实现此种懒加载必须在从对象这边同时满足两个条件:

1、lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)

2、fetch=select。

3、 many-to-one懒加载

此关联关系的懒加载和one-to-one的懒加载一样都是可要可不要的,因为对执行效率的提高都不是非常明显。虽然多对一与一对一关系方式相同,但是在Hibernate中多对一时,默认是进行懒加载的。另外有一点需要注意的是懒加载并不会区分集合属性里面是否有值,即使是没有值,他依然会使用懒加载。实现此种懒加载必须在从对象这边同时满足两个条件

1、lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)

2、fetch=select

4、 many-to-many懒加载

此关联关系的懒加载和one-to-many的懒加载一样对程序的执行效率的提高都是非常明显的。

实现此种懒加载必须在从对象这边同时满足两个条件:

1、lazy!=false(lazy的属性有三个选项分别为:no-proxy、false和proxy)

2、fetch=select

能够懒加载的对象都是被改过的代理对象,当相应的对象没有关闭时,访问这些懒加载对象的属性(getId和getClass除外)Hibernate会初始化这些代理,或用hibernate.initalize(proxy)来初始化代理对象;当关闭session后在访问懒加载的对象就会出现异常。

27. 类(Class)的延迟加载:

◆设置标签中的lazy=”true”,或是保持默认(即不配置lazy属性)

◆ 如果lazy的属性值为true,那么在使用load方法加载数据时,只有确实用到数据的时候才会发出sql语句;这样有可能减少系统的开销。

注意:在class标签上配置的lazy属性不会影响到关联对象!


28. Hiberbate 优化方法有那些?

【参考答案】

1) 尽量使用many-to-one,避免使用one-to-many

2) 灵活使用单向one-to-many

3) 不用一对一,使用多对一代替一对一

4) 配置对象缓存,不使用集合缓存

5) 一对多使用Bag 多对一使用Set

6) 继承使用显示多态HQL:from object polymorphism="exlicit" 避免查处所有对象

7) 消除大表,使用二级缓存

29. 如何设置Hibernate 二级缓存

1、首先要打开二级缓存,在hibernate.cfg.xml 中添加如下配置:true

2、Hibernate 的二级缓存使用第三方的缓存工具来实现,所以我们需要指定Hibernate使用哪个缓存工具。如下配置指定Hibernate 使用EhCache 缓存工具。

org.hibernate.cache.EhCacheProvider

3、 Hibernate 在默认情况下并不会对所有实体对象进行缓存,所以,我们需要指定缓存哪些对象,在实体对象的映射文件中(相应的标签内部),添加如下配置:usage="read-only"是“只读”缓存策略。

30. Hibernate 有哪几种查询数据的方法?

【参考答案】

hibernate 查询有三种方式:HQL 查询、结构化SQL 查询、QBC 查询

31. 介绍hibernate 延持加载属性

【参考答案】Hibernate 通过lazy 来指定加载策略,一般值为true 或false,。设为flase 表示立即加载,true 表过延迟加载。

32. 简述Hibernate 和JDBC 的优缺点? 如何书写一个one to many 配置文件

1、封装了jdbc,简化了很多重复性代码。

2、简化了DAO 层编码工作,使开发更对象化了。

3、移植性好,支持各种数据库,如果换个数据库只要在配置文件中变换配置就可以了,不用改变hibernate 代码。

4、支持透明持久化,因为hibernate 操作的是纯粹的(pojo)java 类,没有实现任何接口,没有侵入性。

33. Hibernate 对象有几种状态?如何转换

共3 种状态,分别是:Transient 状态(瞬时)、Persient 状态(持久)、Detached(脱管状态)状态。

34. hibernate 有哪五个核心接口。

Configuration 接口,SessionFactory 接口,Session 接口,Transaction 接口,Query 和Criteria接口

35. Hibernate 中有几种关系映射

主要有单向一对一、单向一对多、单向多对一、单向多对多、双向一对一、双向一对多、双向多对多。

36. 什么是懒加载 懒加载用代理技术实现  如何解决session关闭导致的懒加载问题 解决的方案有缺点吗 

  1 懒加载 真正需要数据的时候才向数据库发送sql,比如调用load方法,不会发出sql,而在加载对象属性时才发出了sql,实现了数据的延迟加载,get则不然

  2 使用openSessionInView模式解决,实则是一个过滤器,保持session一直在view一直打开

    1 session范围扩大,从dao扩展到了其他的层,session所暂用的资源不能得到及时的释放,效率下降

    2 事务扩大了

37. hibernate 实体的3种状态 

    1  瞬时状态 :刚new出来的对象,与session没关联,调用delete方法也会使对象进入瞬时状

    2  持久化状态:调用session的api,如save saveorupdate,load get进入持久化状态,属性的改变在事务提交的时候同步数据库

    3  脱管状态 :调用了session的clear或者close evit 都使对象脱离了session的管理,状态发生改变不会影响到数据库

38. hibernate 的原理步骤 核心类

答: 

1).读取配置文件;

2).创建SessionFactory(安全);

3).创建session(不安全);

4).开启事务;

5).进行Crud操作(save,update,saveOrUpdate,load,get方法);

6).提交事务;

7).关闭session;

8).关闭SessionFactory;

核心类:

1).Configuration:读取配置文件;

2).SessionFactory:通过Configuration的实例创建,是线程安全的;

3).Session:通过SessionFactory的实例创建,线程不安全;

4).Transaction:事务管理

39. hibernate 的经验 (如 大数据处理 性能优化 有什么经验 最佳实践)

      1 当session关闭仍导致懒加载问题,可使用openSessionInView模式来解决

      2 sql优化九大原则

      3 配置二级缓存EHCache

      4 对于内容较大的字段使用懒加载

      5 api的正确使用,第一次使用list,之后使用iterbate

      6 关联优化

      7 项目上线后把hql的输出关闭

      8 大数据量的处理

          掺入大数据

          1 分批刷新,清除缓存

          2 使用无状态的session

          3 更新 exeuteupdate

          查询: 分页机制

                setFirstresult(起始位置) setMaxResult(一次取几条)

      9 session无法控制数量,导致缓存溢出

      10 无法与第三方系统共存,否则缓存无法控制


40. 谈谈Hibernate与Ibatis的区别,哪个性能会更高一些

Ibatis相当较为简单,容易上手,Hibernate比较复杂,门槛较高。如果系统需要处理数据量很大,性能要求很高,需要执行高度优化的sql语句才能达到性能要求,则此时Ibatis会比较好。

对不同数据库支持方面Hibernate较好,因为Ibatis需要修改的字段较多。另外Hibernate现已成为主流的o/r Mapping框架,开发效率高。

41. hibernate注解

答:1.@Entity

        @Table(name="表名")  标记为持久类映射

2.@Id @GeneratedValue    主键生成机制

3.@ElementCollection    集合映射

4.@OneToMany    一对多

5.@ManyToMany  多对多

你可能感兴趣的:(2019年Java面试题(十六) Hibernate 2019-04-27)