Hibernate面试问题

SessionFactory.getCurrentSession() 与 SessionFactory.openSession()的区别
1. openSession()永远创建一个新的session;getCurrentSession()当上下文存在一个session时,不创建新的session对象,如果没有则创建新的session对象。
2. getCurrentSession创建的线程会再失误回滚或者提交结束后自动关闭,openSession必须手动关闭
3. getCurrentSession()创建的session会绑定到当前线程,openSession()不会绑定。


Hibernate中的三种对象状态Transient,Persistent,Detached
Transient: 用new创建的对象,没有处于session的缓存中,也没有存入数据库,称为临时对象。
Persistent:通过save方法,加入到Session缓存中,并保存到数据库,成为持久化对象。
Detached: 当session对象被关闭或者缓存被清空时,被创建的对象脱离了session,但仍存在内存中,被称为临时对象。




load与get方法的区别
1. 检索执行机制上的对比
get方法直接从数据库中检索,立即发出SQL语句。
load方法首先查找Session的persistent context中是否有缓存对象,如果有需要加载的对象,直接返回,如果没有则判断是否是lazy strategy。如果不是lazy,访问数据库检索,查到返回记录,查不到就跑出异常。如果是lazy策略,则创建一个代理对象,对象的initialzied属性为false,target属性为null。在访问获得的代理对象的属性时,才检索数据库,如果找到记录则把记录的对象复制到代理对象的target上,并把initialized属性设置为true,如果没有找到抛出异常。

2. load方法的加载过程
a. 查询session缓存:查session缓存,看该id对应的对象是否存在
b. 缓存中没有这个对象就创建代理
c. 当需要访问代理对象的属性时,hibernate就去查询二级缓存和数据库,没有这条数据就抛出异常。

3. get方法的加载过程
get方法不能使用延迟加载。首先hibernate会确认该id对应的数据是否存在,首先在session缓存中查找,然后再二级缓存中查找,还没找到就检索数据库,数据库中没有则返回null。
注意*:当get方法在查询session缓存时,存在一种可能是找到的对象是刚被之前load操作创建的代理对象,还不是真真的实体对象,也就是说该代理对象还没有加载数据,那么get方法还是会继续查询二级缓存和数据库,但返回的还是找到的代理对象,只不过该代理对象已经被加载了数据。

4. 返回结果不同
load方法检索不到会抛出org.hibernate.ObjectNotFoundException异常
get方法检索不到返回null

update()方法效率低,因为更新类型一个字段需要更新该类型的全部字段。

对Persistent对象位于数据库缓存中,且以保存在数据库中。当缓存中的对象与数据库中对象数据存在不一致时,当session关闭时,会自动发出update语句,更新所有字段。


性能优化


三种缓存
一级缓存:事物级缓存,session内共享,随着session的消亡而消亡
二级缓存:sessionFactory级别的缓存,能够在session间共享,需要第三方软件支持
查询缓存:查询语句相同时使用。

事务的并发处理
事务:ACID,
1. 原子性atomic,
2. 一致性consistency
3. 隔离性Isolation
4. 持久性/永久性Durability

脏读:读了另一个事务没有提交的值
不可重复读:读两次数据的值不同,由于另一个事务的更新操作
幻读:读两次数据的值不同,由于另一个事务的插入删除操作。

数据库事务隔离机制
read-uncommitted: 允许读没有提交的事务的数据,上述3中都不能限制,取值为1;
read-committed: 提交后才能读,不会出现脏读,不能限制不可重复读,和幻读,取值为2;
repeatable-read:读完数据后给数据加锁,防止别的事务更新。取值为4;
serializable:按序执行事务,效率太低。取值为8;

Hibernate事务隔离级别,通过hibernate.connection.isolation的值来设置
hibernate.connection.isolation = 2 //选择read-committed

用悲观锁解决repeatable read问题,借助数据库的锁实现
session.load(Account.Class,1,LockMode.UPGRADE);//让数据库给读取的数据加锁
SQL语句在最后加上“for update”;

乐观锁:设置一个版本字段,每次提交时检查版本字段是否更新
实现方式,在字段上加上注解@Version

1+N问题,用list方式取数据,发出1条select语句获取对象的同时产生了N条关联对象的select语句
一个对象关联另外一个对象,取一个对象会取出他关联的对象。因为@ManyToOne默认的fetchType = Eager。
解决方案:
①将fetchType设置为Lazy,在需要取得关联对象时,才发出SQL语句
②BatchSize(size = 5)一次性取出5个关联对象
③Join Fetch:做一次外连接,在取出对象的同时,取出关联对象。

List与Iterator的区别
1. List取完整对象,Iterator只取对象的id。用到这个对象的内容之后在发出SQL语句查询
2. Iterator可以利用缓存,list不行。调用两次list会产生发送两次查询语句取出对象。调用两次Iterator也会发出两次获得id的SQL,但是第二次获取对象属性时,会调用缓存的内容,不发出SQL。

猜你喜欢

转载自mir-tempo.iteye.com/blog/2148177