zoukankan      html  css  js  c++  java
  • Hibernate常见面试知识点<转>

    1.  Hibernate中find和iterate的区别?

    find方法和iterator方法的区别

    (1) iterator首先会获取符合条件的记录的id,再跟据id在本地缓存中查找数据,查找不到的再在数据库中查找,结果再存在缓存中。N+1条SQL语句。

    (2) find根据生成的SQL语句,直接访问数据库,查到的数据存在缓存中,一条SQL语句。



    2. 为什么要用Hibernate框架,它有什么优势?

    答:至于我们为什么要用Hibernate,就从Hibernate的四个优点来说:

    首先、Hibernate对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。

    其次、Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现,它很大程度的简化了DAO层编码工作。

    再次、Hibernate使用Java的反射机制,而不是字节码增强程序类实现透明性。

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


    3. Hibernate的工作原理是什么? 
    Hibernate的工作原理:

    1.读取并解析Hibernate核心配置文件hibernate.cfg.xml
    2.读取并解析Hibernate映射文件,创建SessionFactory
    3.打开Sesssion
    4.创建事务Transation 
    5.持久化操作
    6.提交事务
    7.关闭Session
    8.关闭SesstionFactory





    4.Hibernate是如何延迟加载?

    延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。在Hibernate中提供了对实体对象的延迟加载、对集合的延迟加载和对属性的延迟加载。

    当Hibernate在查询数据的时候,数据并没有存储在内存中,当程序真正对数据的进行操作时,持久化对象才存在于内存中,这就实现了延迟加载,它节省了服务器的内存开销,从而提高了服务器的性能。 

    5.Hibernate中怎样实现类之间的关系? (如:一对多、多对多的关系) 
        类与类之间的关系主要体现在表与表之间的关系进行操作,它们都是对对象进行操作,我们程序中把所有的表与类都映射在一起,它们通过配置文件中的many-to-one、one-to-many、many-to-many来表示类之间的关系。

    6. 说下Hibernate的缓存机制?

    缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。

    缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期。

    Hibernate的缓存包括Session的缓存和SessionFactory的缓存,其中SessionFactory的缓存又可以分为两类:内置缓存和外置缓存。Session的缓存是内置的,不能被卸载,也被称为Hibernate的第一级缓存。SessionFactory的内置缓存和Session的缓存在实现方式上比较相似,前者是SessionFactory对象的一些集合属性包含的数据,后者是指Session的一些集合属性包含的数据。SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来,SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的拷贝,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的第二级缓存。


    7.如何优化Hibernate?

    初用HIBERNATE的人也许都遇到过性能问题,实现同一功能,用HIBERNATE与用JDBC性能相差十几倍很正常,如果不及早调整,很可能影响整个项目的进度。

      大体上,对于HIBERNATE性能调优的主要考虑点如下:

      ? 数据库设计调整

      ? HQL优化

      ? API的正确使用(如根据不同的业务类型选用不同的集合及查询API)

      ? 主配置参数(日志,查询缓存,fetch_size, batch_size等)

      ? 映射文件优化(ID生成策略,二级缓存,延迟加载,关联优化)

      ? 一级缓存的管理

      ? 针对二级缓存,还有许多特有的策略

      ? 事务控制策略。

      1、 数据库设计

      a) 降低关联的复杂性

      b) 尽量不使用联合主键

      c) ID的生成机制,不同的数据库所提供的机制并不完全一样

      d) 适当的冗余数据,不过分追求高范式

      2、 HQL优化

      HQL如果抛开它同HIBERNATE本身一些缓存机制的关联,HQL的优化技巧同普通的SQL优化技巧一样,可以很容易在网上找到一些经验之谈。

      3、 主配置

      a) 查询缓存,同下面讲的缓存不太一样,它是针对HQL语句的缓存,即完全一样的语句再次执行时可以利用缓存数据。但是,查询缓存在一个交易系统(数据变更频繁,查询条件相同的机率并不大)中可能会起反作用:它会白白耗费大量的系统资源但却难以派上用场。

      b) fetch_size,同JDBC的相关参数作用类似,参数并不是越大越好,而应根据业务特征去设置

      c) batch_size同上。

      d) 生产系统中,切记要关掉SQL语句打印。

      4、 缓存

      a) 数据库级缓存:这级缓存是最高效和安全的,但不同的数据库可管理的层次并不一样,比如,在ORACLE中,可以在建表时指定将整个表置于缓存当中。

      b) SESSION缓存:在一个HIBERNATE SESSION有效,这级缓存的可干预性不强,大多于HIBERNATE自动管理,但它提供清除缓存的方法,这在大批量增加/更新操作是有效的。比如,同时增加十万条记录,按常规方式进行,很可能会发现OutofMemeroy的异常,这时可能需要手动清除这一级缓存:Session.evict以及Session.clear

      c) 应用缓存:在一个SESSIONFACTORY中有效,因此也是优化的重中之重,因此,各类策略也考虑的较多,在将数据放入这一级缓存之前,需要考虑一些前提条件:

      i. 数据不会被第三方修改(比如,是否有另一个应用也在修改这些数据?)

      ii. 数据不会太大

      iii. 数据不会频繁更新(否则使用CACHE可能适得其反)

      iv. 数据会被频繁查询

      v. 数据不是关键数据(如涉及钱,安全等方面的问题)。

      缓存有几种形式,可以在映射文件中配置:read-only(只读,适用于很少变更的静态数据/历史数据),nonstrict-read-write,read-write(比较普遍的形式,效率一般),transactional(JTA中,且支持的缓存产品较少)

      d) 分布式缓存:同c)的配置一样,只是缓存产品的选用不同,在目前的HIBERNATE中可供选择的不多,oscache, jboss cache,目前的大多数项目,对它们的用于集群的使用(特别是关键交易系统)都持保守态度。在集群环境中,只利用数据库级的缓存是最安全的。

      5、 延迟加载

      a) 实体延迟加载:通过使用动态代理实现

      b) 集合延迟加载:通过实现自有的SET/LIST,HIBERNATE提供了这方面的支持

      c) 属性延迟加载:

      6、 方法选用

      a) 完成同样一件事,HIBERNATE提供了可供选择的一些方式,但具体使用什么方式,可能用性能/代码都会有影响。显示,一次返回十万条记录(List/Set/Bag/Map等)进行处理,很可能导致内存不够的问题,而如果用基于游标(ScrollableResults)或Iterator的结果集,则不存在这样的问题。

      b) Session的load/get方法,前者会使用二级缓存,而后者则不使用。

      c) Query和list/iterator,如果去仔细研究一下它们,你可能会发现很多有意思的情况,二者主要区别(如果使用了Spring,在HibernateTemplate中对应find,iterator方法):

      i. list只能利用查询缓存(但在交易系统中查询缓存作用不大),无法利用二级缓存中的单个实体,但list查出的对象会写入二级缓存,但它一般只生成较少的执行SQL语句,很多情况就是一条(无关联)。

      ii. iterator则可以利用二级缓存,对于一条查询语句,它会先从数据库中找出所有符合条件的记录的ID,再通过ID去缓存找,对于缓存中没有的记录,再构造语句从数据库中查出,因此很容易知道,如果缓存中没有任何符合条件的记录,使用iterator会产生N+1条SQL语句(N为符合条件的记录数)

      iii. 通过iterator,配合缓存管理API,在海量数据查询中可以很好的解决内存问题,如:

      while(it.hasNext()){

      YouObject object = (YouObject)it.next();

      session.evict(youObject);

      sessionFactory.evice(YouObject.class, youObject.getId());

      }

      如果用list方法,很可能就出OutofMemory错误了。

      iv. 通过上面的说明,我想你应该知道如何去使用这两个方法了。

      7、 集合的选用

      在HIBERNATE 3.1文档的“19.5. Understanding Collection performance”中有详细的说明。

      8、 事务控制

      事务方面对性能有影响的主要包括:事务方式的选用,事务隔离级别以及锁的选用

      a) 事务方式选用:如果不涉及多个事务管理器事务的话,不需要使用JTA,只有JDBC的事务控制就可以。

      b) 事务隔离级别:参见标准的SQL事务隔离级别

      c) 锁的选用:悲观锁(一般由具体的事务管理器实现),对于长事务效率低,但安全。乐观锁(一般在应用级别实现),如在HIBERNATE中可以定义VERSION字段,显然,如果有多个应用操作数据,且这些应用不是用同一种乐观锁机制,则乐观锁会失效。因此,针对不同的数据应有不同的策略,同前面许多情况一样,很多时候我们是在效率与安全/准确性上找一个平衡点,无论如何,优化都不是一个纯技术的问题,你应该对你的应用和业务特征有足够的了解。

      9、 批量操作

      即使是使用JDBC,在进行大批数据更新时,BATCH与不使用BATCH有效率上也有很大的差别。我们可以通过设置batch_size来让其支持批量操作。

      举个例子,要批量删除某表中的对象,如“delete Account”,打出来的语句,会发现HIBERNATE找出了所有ACCOUNT的ID,再进行删除,这主要是为了维护二级缓存,这样效率肯定高不了,在后续的版本中增加了bulk delete/update,但这也无法解决缓存的维护问题。也就是说,由于有了二级缓存的维护问题,HIBERNATE的批量操作效率并不尽如人意!

      从前面许多要点可以看出,很多时候我们是在效率与安全/准 确性上找一个平衡点,无论如何,优化都不是一个纯技术的问题,你应该对你的应用和业务特征有足够的了解,一般的,优化方案应在架构设计期就基本确定,否则 可能导致没必要的返工,致使项目延期,而作为架构师和项目经理,还要面对开发人员可能的抱怨,必竟,我们对用户需求更改的控制力不大,但技术/架构风险是应该在初期意识到并制定好相关的对策。

      还有一点要注意,应用层的缓存只是锦上添花,永远不要把它当救命稻草,应用的根基(数据库设计,算法,高效的操作语句,恰当API的选择等)才是最重要的。


    8. 在Hibernate中不看数据库,不看XML文件,不看查询语句,怎么样能知道表结构?

    看表结构对应的类文件,比如UserInfo表对应的UserInfo.java文件 

    9. 用过Hibernate吗,用它有什么好处? 
        Hibernate的最大好处就是简化了数据库操作,允许程序员以面向对象的方式来访问数据库,例如我们要查询Users表中的用户信息,通过hibnate可以把某一条Users表中的记录作为一个对象来看待,通过User.getName()或者User.getId()等操作来获取该用户的详细信息,这样就完全统一了上层JAVA或者C#等OO语言中对于数据库的非OO操作了。



    10. Hibernate有哪几种查询数据的方式?
         (1) 导航对象图查询

    (2) OID查询

    (3) HQL查询

    (4) QBC查询

    (5) 本地SQL查询



    11. Hibernate中load方法和get方法的区别?

    load加载方法:

    示例代码

    Users user = (Users)session.load(Users.class, userId);   

    Users user = (Users)session.load(Users.class, userId);



    get加载方法:

    示例代码

    Users user = (Users)session.get(Users.class, userId);  

    Users user = (Users)session.get(Users.class, userId);



    两加载方法区别:

    区别1:如果数据库中没有userId对应的记录,通过get方法加载,则返回的是null值;如果通过load方法加载,则返回一个代理对象,当通过user对象调用某个方法(比如user.getPassword())时,会抛出异常:org.hibernate.ObjectNotFoundException;



    区别2:load支持延迟加载,get不支持延迟加载。

  • 相关阅读:
    Unable To Open Database After ASM Upgrade From Release 11.1 To Release 11.2
    11g Understanding Automatic Diagnostic Repository.
    How to perform Rolling UpgradeDowngrade in 11g ASM
    Oracle 11.2.0.2 Patch 说明
    Pattern Matching Metacharacters For asm_diskstring
    Steps To MigrateMove a Database From NonASM to ASM And ViceVersa
    Upgrading ASM instance from Oracle 10.1 to Oracle 10.2. (Single Instance)
    OCSSD.BIN Process is Running in a NonRAC Environment
    Steps To MigrateMove a Database From NonASM to ASM And ViceVersa
    On RAC, expdp Removes the Service Name [ID 1269319.1]
  • 原文地址:https://www.cnblogs.com/sunliqing/p/3446513.html
Copyright © 2011-2022 走看看