Hibernate面试

1      SessoinFactory

a)        用来产生和管理Session

b)        通常情况下每个应用只需要一个SessionFactory

c)        除非要访间多个数据库的情况

d)        关注两个方法即:openSession getCurrentsession的区别

                       i.      open session每次都是新的,需要close

                       ii.      getCurrentsession从上下文找,如果有,用旧的,如果没有,建新的

1.  用途,界定事务边界

2.  事务提交自动close

3.  上下文配置可参见xml文件中

        <property name="current_session_context_classs">thread</property>

4.  current_session_context_class (jta、thread常用 managed、custom.Class少用)

          a) thread 使用connection 但数据库连接管理事务

          b)jta (全称java transaction api)-java分布式事务管理(多数据库访问)

            jta由中间件提供(jboss WebLogic等,tomcat不支持)

 

2         三种状态区别:

a)         transient:内存中一个对象,没ID,缓存中也没有

b)         persistent:内存中有,缓存中有,数据库有(ID)

c)         detached:内存有,缓存没有,数据库有,ID

 

3 exists 与 in 选哪个?

from Topic t where not exists (select m.id from Msg m where m.topic.id=t.id)

from Topic t where not in(select m.id from Msg m where m.topic.id=t.id)

一般都选择exists ,因为exists的执行效率比in高。

 

 4 java 有内存泄露没?

在语法级别上其实没有,你不用去回收内存,内存自动被垃圾回收器回收了。但是写程序的时候,你调用了一些资源,如连接池或者打开一个文件(io),你打开了必须关闭,垃圾回收器不会自动收集,会造成内存泄露。

Java中的内存泄露当然是指:存在无用但是垃圾回收器无法回收的对象。而且即使有内存泄露问题存在,也不一定会表现出来。 

    Java的一个重要优点就是通过垃圾收集器(Garbage Collection,GC)自动管理内存的回收,程序员不需要通过调用函数来释放内存。因此,很多程序员认为Java不存在内存泄漏问题,或者认为即使有内存泄漏也不是程序的责任,而是GC或 JVM的问题。其实,这种想法是不正确的,因为Java也存在内存泄露,但它的表现与C++不同。

    在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。

简单的说,一个对象没有任何引用,他会被GC;但是如果这个对象一直被引用,就不会被GC,如果你往这个对象添加数据,他就越来越大,就是nused but still referenced,就OOM(outofmemeory)了。

 5 hibernate 中什么是1+N问题?

在Session的缓存中存放的是相互关联的对象图。默认情况下,当Hibernate从数据库中加载Customer对象时,会同时加载所有关联的Order对象(典型的ManyToOne)。以Customer和Order类为例,假定ORDERS表的CUSTOMER_ID外键允许为null,图1列出了CUSTOMERS表和ORDERS表中的记录。



以下Session的find()方法用于到数据库中检索所有的Customer对象:

List customerLists=session.find("from Customer as c");

运行以上find()方法时,Hibernate将先查询CUSTOMERS表中所有的记录,然后根据每条记录的ID,到ORDERS表中查询有参照关系的记录,Hibernate将依次执行以下select语句:

select * from CUSTOMERS;
select * from ORDERS where CUSTOMER_ID=1;
select * from ORDERS where CUSTOMER_ID=2;
select * from ORDERS where CUSTOMER_ID=3;
select * from ORDERS where CUSTOMER_ID=4;

通过以上5条select语句,Hibernate最后加载了4个Customer对象和5个Order对象,在内存中形成了一幅关联的对象图,参见图2。



Hibernate在检索与Customer关联的Order对象时,使用了默认的立即检索策略。这种检索策略存在两大不足:

(1) select语句的数目太多,需要频繁的访问数据库,会影响检索性能。如果需要查询n个Customer对象,那么必须执行n+1次select查询语句。这就是经典的n+1次select查询问题。这种检索策略没有利用SQL的连接查询功能,例如以上5条select语句完全可以通过以下1条select语句来完成:

select * from CUSTOMERS left outer join ORDERS
on CUSTOMERS.ID=ORDERS.CUSTOMER_ID

以上select语句使用了SQL的左外连接查询功能,能够在一条select语句中查询出CUSTOMERS表的所有记录,以及匹配的ORDERS表的记录。

(2)在应用逻辑只需要访问Customer对象,而不需要访问Order对象的场合,加载Order对象完全是多余的操作,这些多余的Order对象白白浪费了许多内存空间。
为了解决以上问题,Hibernate提供了其他两种检索策略:延迟检索策略和迫切左外连接检索策略。延迟检索策略能避免多余加载应用程序不需要访问的关联对象,迫切左外连接检索策略则充分利用了SQL的外连接查询功能,能够减少select语句的数目。

 

解决办法:

a)         @ManyToOne(fetch=FetchType.LAZY)

       //fetch=FetchType.LAZY 解决N+1问题 说明如下:

       //当多对一(@ManyToOne)已经设定属性" fetch=FetchType.LAZY "时

       //只有当需要时(如:t.getCategory().getName()时)才会去获取关联表中数据 可以解决N+1问题

b)         @BatchSize

       //@BatchSize 解决N+1问题 说明如下:

       //在与查询表(此例中为Topic类)关联的表类(此例中为Category类)头处加@BatchSize(size=5)

       //表示每次可查出5条记录 从而减少了select语句的个数

c)         join fetch

       //join fetch 解决N+1问题 说明如下:

       //修改hql语句为--"  from Topic t left join fetch t.category c  "

d)         QBC

       //QBC(Query By Criteria) 解决N+1问题 说明如下:

       //使用QBC的 createCriteria(*.class)执行查询 也可避免N+1问题

 

 6     list和iterate的区别

a)         list取所有

b)         iterate先取 ID,等用到的时候再根据ID来取对象

c)         session中list第二次发出,仍会到数据库査询

d)         iterate 第二次,首先找session 级缓存

 

7         一级缓存和二级缓存和査询缓存

a)         什么是缓存

                      缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。

b)         什么是一级缓存,session级别的缓存

c)         I什么是二级缓存,SessionFactory级别的缓存,可以跨越session存在

                      i.        经常被访间

                      ii.        改动不大不会经常改动

                     iii.        数重有限

d)         打开二级缓存

                      i.        hibernate.cfg.xml 设定:

<property

name= "cache.use_second_level_cache">true</property>

<property

name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

                  ii.        @Cache注解(由hibernate扩展提供)

@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)

 

注:使用EhCache二级缓存 需要导入ehcache-1.2.3.jar及commons-logging-1.0.4.jar包

e)         load默认使用二级缓存,iterate默认使用二级缓存

f)         list默认往二级缓存加数据,但是查询的时候不使用

g)         如果要query用二级缓存,需打开查询缓存

<property name="cache.use_query_cache">true</property>

调用Query的setCachable (true)方法指明使用二级缓存

例如:session.createQuery("from Category").setCacheable(true).list();

h)         缓存算法:

                 i.        LRU  LFU  FIFO

                             1.             Least Recently Used –最近很少被使用

                             2.             Least Frequently Used (命中率高低)

                             3.             First In First Out 按顺序替换

                             memoryStoreEvictionPolicy = "LRU" (ehcache.xml中配置)

 

    事务并发处理

          a)        事务:ACID

                       i.      Atomic Consistency Itegrity Durability

                       事务的原子性、一致性、独立性及持久性事务的原子性是指一个事务要么全部执行,要么不执行.也就是说一个事务不可能只执行了一半就停止了.比如你从取款机取钱,这个事务可以分成两个步骤:1划卡,2出钱.不可能划了卡,而钱却没出来.这两步必须同时完成.要么就不完成.事务的一致性是指事务的运行并不改变数据库中数据的一致性.例如,完整性约束了a+b=10,一个事务改变了a,那么b也应该随之改变.事务的独立性是指两个以上的事务不会出现交错执行的状态.因为这样可能会导致数据不一致.事务的持久性是指事务运行成功以后,就系统的更新是永久的.不会无缘无故的回滚

           b)        事务并发时可能出现的问题

                       1.     第一类丢失更新(Lost Update)

                       2.     dirty read脏读(读到了另一个事务在处理中还未提交的数据)

                       3.     non-repeatable read 不可重复读(同一个事物里,对同一个数据读两回的值是不一样的)

                       4.     second lost update problem 第二类丢失更新(不可重复读的特殊情况)

                       5.     phantom read 幻读(插入与删除问题,在读数据的时候,插入了或删除了数据,影响了读的结果)

                        (只要考虑2,3,5,其他都是特殊情况)

           c)        数据库的事务隔离机制

                      i.        查看 java.sql.Connection 文档

                      ii.        1:read-uncommitted  2:read-committed  4:repeatable read  8:serializable(数字代表对应值)

                                           为什么取值要使用 1 2 4 8 而不是 1 2 3 4

                                           1=0000  2=0010 4=0100 8=1000(位移计算效率高)

                                 1.             只要数据库支持事务,就不可能出现第一类丢失更新

                                 2.             read-uncommitted(允许读取未提交的数据) 会出现dirty read, phantom-read,non-repeatable read 问题

                                 3.             read-commited(读取已提交的数据 项目中一般都使用这个)不会出现dirty read,因为只有另 一个事务提交才会读出来结果,但仍然会出现

non-repeatable read 和 phantom-read 使用read-commited机制可用悲观锁 乐观锁来解决non-repeatable read 和 phantom-read问题

                                 4.            repeatable read(事务执行中其他事务无法执行修改或插入操作     较安全)

                                 5.            serializable解决一切问题(顺序执行事务 不并发,实际中很少用,效率低)

                                 乐观锁和悲观锁的前提也就是hibernate.conection.isolation=2 也就是隔离级别为read-committed
                                 悲观锁是依赖数据库中的锁,  而乐观锁是在程序中做处理,  所以乐观锁的效率要高

             d)        设定hibernate的事务隔离级别(使用hibernate.connection.isolation配置取值1、2、4、8)

                          i.        hibernate.connection.isolation = 2(如果不设默认依赖数据库本身的级别)

                         ii.        用悲观锁解决repeatable read的问题(依赖于数据库的锁)

                                   1.             select ... for update

                                   2.             使用另一种load方法--load(xx.class , i , LockMode.Upgrade)

                                               a)     LockMode.None无锁的机制,Transaction结束时,切换到此模式

                                               b)     LockMode.read在査询的时候hibernate会自动获取锁

                                               c)     LockMode.write insert  update hibernate 会自动获取锁

                                               d)     以上3种锁的模式,是hibernate内部使用的(不需要设)

                                               e)     LockMode.UPGRADE_NOWAIT是 ORACLE 支持的锁的方式

              e)        Hibernate(JPA)乐观锁定(ReadCommitted)

                          实体类中增加version属性(数据库也会对应生成该字段,初始值为0),并在其get方法前加

                          @Version注解,则在操作过程中没更新一次该行数据则version值加1,即可在事务提交前判断该数据是否被其他事务修改过.

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值