2023年最新Hibernate面试题及答案大全(含详细解析)

这是文章《Hibernate面试问题和答案》的第1部分(共2部分)。

Hibernate是Java应用程序中最广泛使用的ORM(对象关系映射)工具之一。在企业应用程序中,它在数据库操作中被大量使用。因此,在面试之前,我决定写一篇关于Hibernate面试问题的文章,以便帮助你巩固知识。无论你是刚入行还是经验丰富,掌握Hibernate ORM工具的知识都有助于你在面试中取得好成绩。在这里,我提供了一些重要的Hibernate面试问题及答案,帮助你巩固知识并给面试官留下深刻印象。就像其他面试问题文章一样,我可能会在将来添加更多问题到这个列表中,所以你可能想要将其添加到书签中以备将来参考。最近,我已经写了很多关于Hibernate的文章,其中大部分都包含完整的可下载项目。在需要时,我会提供相关参考,并请你查阅以更新知识。

Hibernate面试问题

  1. Hibernate框架是什么?
  2. Java持久化API(JPA)是什么?
  3. 使用Hibernate框架的重要优势有哪些?
  4. Hibernate相比JDBC的优势是什么?
  5. Hibernate框架的一些重要接口是什么?
  6. Hibernate配置文件是什么?
  7. Hibernate映射文件是什么?
  8. 用于Hibernate映射的一些重要注解是什么?
  9. Hibernate SessionFactory是什么,如何配置它?
  10. Hibernate SessionFactory是线程安全的吗?
  11. Hibernate Session是什么,如何获得它?
  12. Hibernate Session是线程安全的吗?
  13. openSession和getCurrentSession有什么区别?
  14. Hibernate Session的get()和load()方法有什么区别?
  15. Hibernate缓存是什么?解释Hibernate一级缓存是什么?
  16. 如何使用EHCache配置Hibernate二级缓存?
  17. 实体Bean的不同状态有哪些?
  18. Hibernate Session merge()方法有什么用?
  19. Hibernate的save()、saveOrUpdate()和persist()方法有什么区别?
  20. 如果实体Bean没有无参数构造函数会发生什么?
  21. 有序集合和无序集合有什么区别,哪个更好?
  22. Hibernate中有哪些集合类型?
  23. 如何在Hibernate中实现连接查询?
  24. 为什么我们不应该将实体类设为final?
  25. HQL是什么,它的好处是什么?
  26. Hibernate中的查询缓存是什么?
  27. 我们可以在Hibernate中执行原生SQL查询吗?
  28. Hibernate支持原生SQL查询有什么好处?
  29. 什么是命名SQL查询?
  30. 命名SQL查询的好处是什么?
  31. Hibernate Criteria API的好处是什么?
  32. 如何在日志文件中记录Hibernate生成的SQL查询?
  33. Hibernate代理是什么,它如何帮助实现延迟加载?
  34. 如何在Hibernate中实现关系型数据库?
  35. Hibernate中事务管理是如何工作的?
  36. 什么是级联,有哪些不同类型的级联?
  37. 如何在Hibernate应用中集成log4j日志记录?
  38. 如何在Hibernate框架中使用应用程序服务器JNDI DataSource?
  39. 如何将Hibernate与Spring框架集成?
  40. HibernateTemplate类是什么?
  41. 如何在Servlet或Struts2 web应用程序中集成Hibernate?
  42. Hibernate框架使用了哪些设计模式?
  43. 在Hibernate框架中应该遵循哪些最佳实践?
  44. Hibernate验证器框架是什么?
  45. Hibernate Tools Eclipse插件有什么好处?

整理好的面试问题和答案

这是文章《Hibernate面试问题和答案》的第2部分(共2部分)。

一、Hibernate Framework是什么?

Hibernate Framework是一个基于Java的ORM(对象关系映射)工具,它提供了将应用程序领域模型对象映射到关系数据库表的框架,反之亦然。Hibernate提供了Java持久性API的参考实现,使其成为一种具有松散耦合优势的理想ORM工具。我们可以使用Hibernate持久性API进行CRUD操作。Hibernate框架通过JPA注解和基于XML的配置提供将普通的Java对象映射到传统数据库表的选项。类似地,Hibernate配置是灵活的,可以从XML配置文件或以编程方式完成。如果您想快速了解Hibernate框架的用法,可以通过阅读Hibernate入门教程来获取概述。

二、Java持久性API(JPA)是什么?

Java持久性API(JPA)提供了管理应用程序中的关系数据的规范。当前JPA版本2.1始于2011年7月,是JSR 338。JPA 2.1于2013年5月22日获得最终批准。JPA规范在javax.persistence包中以注解的形式定义。使用JPA注解有助于我们编写与具体实现无关的代码。

三、使用Hibernate Framework的重要优势有哪些?

使用Hibernate框架的一些重要优势包括:

  • Hibernate消除了使用JDBC时伴随而来的所有样板代码,并负责管理资源,因此我们可以专注于业务逻辑。
  • Hibernate框架支持XML和JPA注解,使我们的代码实现独立。
  • Hibernate提供了一个强大的查询语言(HQL),类似于SQL。然而,HQL完全面向对象,并理解继承、多态和关联等概念。
  • Hibernate是来自Red Hat社区的开源项目,被全球广泛使用。这使得它比其他项目更好,因为学习曲线较小,有大量的在线文档和论坛上的帮助资源。
  • Hibernate很容易与其他Java EE框架集成,它非常流行,Spring Framework内置了与Hibernate集成的支持。
  • Hibernate通过使用代理对象支持延迟初始化,并在需要时才执行实际的数据库查询。
  • Hibernate缓存帮助我们获得更好的性能。
  • 针对特定的数据库供应商功能,Hibernate是合适的,因为我们可以执行原生的SQL查询。总的来说,在当前市场上,Hibernate是ORM工具的最佳选择,它包含了您在ORM工具中将需要的所有功能。

四、Hibernate相对于JDBC的优势是什么?

Hibernate框架相对于JDBC的一些重要优点包括:

  • Hibernate消除了使用JDBC API时涉及的大量样板代码,使代码更加清晰和可读。
  • Hibernate支持继承、关联和集合操作,而这些功能在JDBC API中并不存在。
  • Hibernate隐式提供事务管理,在实际上,大多数查询都不能在事务外执行。而在JDBC API中,我们需要编写用于事务管理的代码,例如提交和回滚。请参阅JDBC事务管理。
  • JDBC API抛出SQLException,它是一个受检异常,因此我们需要编写大量的try-catch代码块。大多数情况下,在每个JDBC调用中都是多余的,并且仅用于事务管理。Hibernate封装了JDBC异常并抛出JDBCException或HibernateException不受检异常,因此我们不需要编写处理异常的代码。Hibernate内置的事务管理消除了try-catch代码块的使用。
  • Hibernate查询语言(HQL)更加面向对象,类似于Java编程语言。对于JDBC,我们需要编写原生的SQL查询。
  • Hibernate支持缓存,这对性能更好,而JDBC查询不会被缓存,因此性能较低。
  • Hibernate提供了创建数据库表的选项,而对于JDBC,表必须已经存在于数据库中。
  • Hibernate配置帮助我们使用类似于JDBC的连接以及JNDI数据源进行连接池。这是企业应用中非常重要的功能,在JDBC API中完全缺失。
  • Hibernate支持JPA注解,因此代码与实现无关,可以轻松替换为其他ORM工具。JDBC代码与应用程序之间的耦合非常紧密。

五、Hibernate框架的一些重要接口是什么?

Hibernate框架的一些重要接口包括:

  1. SessionFactory (org.hibernate.SessionFactory):SessionFactory是一个不可变的线程安全的编译映射缓存,用于单个数据库。我们需要初始化SessionFactory一次,然后我们可以缓存并重用它。SessionFactory实例用于获取用于数据库操作的Session对象。
  2. Session (org.hibernate.Session):Session是一个单线程的、短生命周期的对象,表示应用程序和持久存储之间的对话。它包装了JDBC的java.sql.Connection,并作为org.hibernate.Transaction的工厂工作。我们应该只在需要时打开session,并在使用完毕后立即关闭它。Session对象是java应用程序代码和hibernate框架之间的接口,并提供CRUD操作的方法。
  3. Transaction (org.hibernate.Transaction):Transaction是一个单线程的、短生命周期的对象,被应用程序用来指定工作的原子单元。它抽象了应用程序与底层JDBC或JTA事务的关系。在某些情况下,一个org.hibernate.Session可能跨越多个org.hibernate.Transaction。

六、什么是hibernate配置文件?

Hibernate配置文件包含特定于数据库的配置,用于初始化SessionFactory。我们在hibernate配置xml文件中提供数据库凭据或JNDI资源信息。hibernate配置文件的其他重要部分是方言(Dialect)信息,以便hibernate了解数据库类型和映射文件或类的详细信息。

七、什么是Hibernate映射文件?

Hibernate映射文件用于定义实体bean字段和数据库表列的映射。我们知道JPA注解可以用于映射,但有时当我们使用第三方类且不能使用注解时,XML映射文件会派上用场。

八、列举一些在Hibernate映射中使用的重要注解。

Hibernate支持JPA注解,它在org.hibernate.annotations包中还有一些其他注解。使用的一些重要JPA和hibernate注解包括:

  1. javax.persistence.Entity:与模型类一起使用,以指定它们是实体bean。
  2. javax.persistence.Table:与实体bean一起使用,以定义数据库中相应的表名。
  3. javax.persistence.Access:用于定义访问类型,可以是字段或属性。默认值是字段,如果您希望hibernate使用getter/setter方法,则需要将其设置为property。
  4. javax.persistence.Id:用于定义实体bean中的主键。
  5. javax.persistence.EmbeddedId:用于定义实体bean中的复合主键。
  6. javax.persistence.Column:用于定义数据库表中的列名。
  7. javax.persistence.GeneratedValue:用于定义用于生成主键的策略。与javax.persistence.GenerationType枚举一起使用。
  8. javax.persistence.OneToOne:用于定义两个实体bean之间的一对一映射。我们有其他类似的注解,如OneToManyManyToOneManyToMany
  9. org.hibernate.annotations.Cascade:用于定义两个实体bean之间的级联,与映射一起使用。它与org.hibernate.annotations.CascadeType一起工作。
  10. javax.persistence.PrimaryKeyJoinColumn:用于定义外键的属性。与org.hibernate.annotations.GenericGeneratororg.hibernate.annotations.Parameter一起使用。

以下是显示这些注解用法的两个类:

package com.Olivia.hibernate.model;

import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.Cascade;

@Entity
@Table(name = "EMPLOYEE")
@Access(value=AccessType.FIELD)
public class Employee {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "emp_id")
	private long id;

	@Column(name = "emp_name")
	private String name;

	@OneToOne(mappedBy = "employee")
	@Cascade(value = org.hibernate.annotations.CascadeType.ALL)
	private Address address;

	//getter setter方法
}
package com.Olivia.hibernate.model;

import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;

@Entity
@Table(name = "ADDRESS")
@Access(value=AccessType.FIELD)
public class Address {

	@Id
	@Column(name = "emp_id", unique = true, nullable = false)
	@GeneratedValue(generator = "gen")
	@GenericGenerator(name = "gen", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") })
	private long id;

	@Column(name = "address_line1")
	private String addressLine1;

	@OneToOne
	@PrimaryKeyJoinColumn
	private Employee employee;

	//getter setter方法
}

九、什么是Hibernate SessionFactory,如何进行配置?

SessionFactory是用于获取Session对象的工厂类。SessionFactory负责读取hibernate配置参数并连接到数据库,并提供Session对象。通常一个应用程序有一个单一的SessionFactory实例,服务客户端请求的线程从这个工厂获取Session实例。SessionFactory的内部状态是不可变的。一旦创建,这个内部状态就被设置。这个内部状态包括所有关于对象/关系映射的元数据。SessionFactory还提供获取类元数据和Statistics实例的方法,以获取查询执行统计、二级缓存详细信息等。

十、Hibernate的SessionFactory是线程安全的吗?

SessionFactory的内部状态是不可变的,所以它是线程安全的。多个线程可以同时访问它以获取Session实例。

十一、什么是Hibernate会话,以及如何获取它?

Hibernate Session是java应用程序层和hibernate之间的接口。这是用于执行数据库操作的核心接口。会话的生命周期由事务的开始和结束绑定。Session提供执行持久对象的创建、读取、更新和删除操作的方法。我们可以使用Session对象执行HQL查询、SQL原生查询和创建条件。

十二、Hibernate会话是线程安全的吗?

Hibernate Session对象不是线程安全的,每个线程应该获取自己的session实例,并在工作完成后关闭它。

十三、openSession和getCurrentSession之间有什么区别?

Hibernate SessionFactory的getCurrentSession()方法返回绑定到上下文的session。但是为了使其工作,我们需要在hibernate配置文件中配置它。由于这个session对象属于hibernate上下文,我们不需要关闭它。一旦session工厂关闭,这个session对象也会被关闭。

<property name="hibernate.current_session_context_class">thread</property>

Hibernate SessionFactory的openSession()方法总是打开一个新的session。一旦完成所有数据库操作,我们应该关闭这个session对象。在多线程环境中,我们应该为每个请求打开一个新的session。还有另一个方法openStatelessSession()返回无状态的session,更多细节和示例请阅读Hibernate openSession vs getCurrentSession

十四、Hibernate Session的get()方法和load()方法有什么区别?

Hibernate session带有不同的方法来从数据库加载数据。get和load是最常用的方法,乍一看它们似乎相似,但它们之间有一些区别。

  1. get()在调用时立即加载数据,而load()返回一个代理对象,并且只在实际需要时加载数据,所以load()更好,因为它支持延迟加载。
  2. 由于load()在找不到数据时抛出异常,我们应该只在确定数据存在时使用它。
  3. 当我们想要确保数据存在于数据库中时,应该使用get()。

有关差异的澄清,请阅读Hibernate get vs load

十五、什么是Hibernate缓存?解释一下Hibernate的一级缓存。

顾名思义,hibernate缓存查询数据以使我们的应用程序更快。如果使用正确,Hibernate Cache可以在获得快速应用程序性能方面非常有用。缓存背后的思想是减少数据库查询的数量,从而减少应用程序的吞吐时间。Hibernate一级缓存与Session对象相关联。Hibernate一级缓存默认启用,没有办法禁用它。但是hibernate提供了一些方法,我们可以通过这些方法从缓存中删除选定的对象或完全清除缓存。在一个会话中缓存的任何对象对其他会话都不可见,当会话关闭时,所有缓存的对象也将丢失。更好的解释,请阅读Hibernate First Level Cache

十六、如何使用EHCache配置Hibernate二级缓存?

EHCache是利用hibernate二级缓存的最佳选择。在hibernate应用程序中启用EHCache需要以下步骤。

  • 在您的maven项目中添加hibernate-ehcache依赖项,如果不是maven,则添加相应的jar。
    <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>4.3.5.Final</version>
    </dependency>
        
  • 在hibernate配置文件中添加以下属性。
    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
                 
    <!-- 对于单例工厂 -->
    <!-- <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>
    -->
                  
    <!-- 启用二级缓存和查询缓存 -->
    <property name="hibernate.cache.use_second_level_cache">true</property>
    <property name="hibernate.cache.use_query_cache">true</property>
    <property name="net.sf.ehcache.configurationResourceName">/myehcache.xml</property>
        
  • 创建EHCache配置文件,示例文件myehcache.xml如下所示。
    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
        monitoring="autodetect" dynamicConfig="true">
     
        <diskStore path="java.io.tmpdir/ehcache" />
     
        <defaultCache maxEntriesLocalHeap="10000" eternal="false"
            timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30"
            maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU" statistics="true">
            <persistence strategy="localTempSwap" />
        </defaultCache>
     
        <cache name="employee" maxEntriesLocalHeap="10000" eternal="false"
            timeToIdleSeconds="5" timeToLiveSeconds="10">
            <persistence strategy="localTempSwap" />
        </cache>
     
        <cache name="org.hibernate.cache.internal.StandardQueryCache"
            maxEntriesLocalHeap="5" eternal="false" timeToLiveSeconds="120">
            <persistence strategy="localTempSwap" />
        </cache>
     
        <cache name="org.hibernate.cache.spi.UpdateTimestampsCache"
            maxEntriesLocalHeap="5000" eternal="true">
            <persistence strategy="localTempSwap" />
        </cache>
    </ehcache>
        
  • 使用@Cache注解和要使用的缓存策略来注解实体bean。例如,
    import org.hibernate.annotations.Cache;
    import org.hibernate.annotations.CacheConcurrencyStrategy;
    
    @Entity
    @Table(name = "ADDRESS")
    @Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="employee")
    public class Address {
    
    }
        

就是这样,我们完成了。Hibernate将使用EHCache进行二级缓存,阅读Hibernate EHCache Example获取完整的示例和解释。

十七、实体Bean有哪些不同的状态?

实体bean实例可以存在于三种状态之一。

  1. 瞬时态(Transient):当一个对象从未被持久化或与任何会话关联时,它处于瞬时态。可以通过调用save()、persist()或saveOrUpdate()使瞬时实例变为持久态。可以通过调用delete()使持久实例变为瞬时态。
  2. 持久态(Persistent):当一个对象与唯一的会话关联时,它处于持久态。任何由get()或load()方法返回的实例都是持久态的。
  3. 游离态(Detached):当一个对象之前是持久态的,但当前不与任何会话关联时,它处于游离态。可以通过调用update()、saveOrUpdate()、lock()或replicate()使游离实例变为持久态。也可以通过调用merge()使瞬时态或游离态实例的状态作为新的持久实例变为持久态。

十八、Hibernate Session merge() 方法的用途是什么?

Hibernate merge可用于更新现有值,但是此方法从传递的实体对象创建一个副本并返回它。返回的对象是持久上下文的一部分,并被跟踪任何更改,传递的对象不被跟踪。对于示例程序,请阅读Hibernate merge

十九、Hibernate的save()、saveOrUpdate()和persist()方法有何不同之处?

Hibernate save可用于将实体保存到数据库。save()的问题在于它可以在没有事务的情况下被调用,如果我们有映射实体,那么只有主对象被保存,导致数据不一致。此外,save立即返回生成的id。Hibernate persist类似于带有事务的save。我觉得它比save更好,因为我们不能在事务边界之外使用它,所以所有对象映射都被保留。而且persist不会立即返回生成的id,所以数据持久化在需要时发生。Hibernate saveOrUpdate根据提供的数据导致插入或更新查询。如果数据存在于数据库中,则执行更新查询。我们也可以在没有事务的情况下使用saveOrUpdate(),但如果会话没有被刷新,你将面临映射对象没有被保存的问题。有关这些方法的用法,请阅读Hibernate save vs persist

二十、如果实体bean没有无参构造函数会发生什么?

Hibernate使用Reflection API来创建Entity bean的实例,通常当你调用get()或load()方法时。为此使用Class.newInstance()方法,它需要无参构造函数。所以如果在实体bean中没有无参构造函数,hibernate将无法实例化它,你将得到HibernateException

二十一、排序集合和有序集合有什么区别,哪一个更好?

当我们使用Collection API排序算法对集合进行排序时,它被称为排序列表。对于小集合,这不是很大的开销,但对于大集合,它可能导致性能变慢和OutOfMemory错误。此外,实体bean应该实现ComparableComparator接口才能工作,在java对象列表排序阅读更多内容。如果我们使用Hibernate框架从数据库加载集合数据,我们可以使用它的Criteria API来使用”order by”子句来获取有序列表。下面的代码片段向您展示了如何获取它。

List<Employee> empList = session.createCriteria(Employee.class)
						.addOrder(Order.desc("id")).list();

有序列表比排序列表更好,因为实际的排序是在数据库级别完成的,这很快并且不会导致内存问题。

二十二、在Hibernate中有哪些收集类型?

hibernate中有五种集合类型用于一对多关系映射。

  1. Bag(包)
  2. Set(集)
  3. List(列表)
  4. Array(数组)
  5. Map(映射)

二十三、如何在Hibernate中实现连接操作?

在hibernate中有各种方法可以实现连接。

  • 使用诸如一对一、一对多等关联。
  • 在HQL查询中使用JOIN。还有另一种形式”join fetch”可以同时加载关联数据,没有延迟加载。
  • 我们可以触发原生sql查询并使用join关键字。

二十四、为什么我们不应该将实体类设为最终类?

Hibernate使用代理类来实现数据的延迟加载,只有在需要时才加载。这是通过扩展实体bean来完成的,如果实体bean是最终的,那么延迟加载将不可能,从而导致性能低下。

二十五、什么是HQL以及它的好处?

Hibernate Framework带有一个强大的面向对象的查询语言——Hibernate查询语言(HQL)。它与SQL非常相似,只是我们使用对象而不是表名,这使其更接近面向对象编程。Hibernate查询语言不区分大小写,除了java类和变量名。所以SeLeCT与sELEct与SELECT相同,但com.Olivia.model.Employee与com.Olivia.model.EMPLOYEE不同。HQL查询被缓存,但我们应该尽可能避免使用它,否则我们将不得不处理关联。然而,由于面向对象的方法,它是比原生sql查询更好的选择。在HQL Example阅读更多内容。

二十六、在Hibernate中,查询缓存是指什么?

Hibernate为查询结果集实现了一个缓存区域,它与hibernate二级缓存紧密集成。这是一个可选功能,需要在代码中采取额外步骤。这只对使用相同参数频繁运行的查询有用。首先,我们需要在hibernate配置文件中配置以下属性。

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

在代码中,我们需要使用Query的setCacheable(true)方法,快速示例如下。

Query query = session.createQuery("from Employee");
query.setCacheable(true);
query.setCacheRegion("ALL_EMP");

二十七、我们能在Hibernate中执行原生的SQL查询吗?

Hibernate提供了通过使用SQLQuery对象执行原生SQL查询的选项。对于正常场景,然而这不是推荐的方法,因为我们失去了与hibernate关联和hibernate一级缓存相关的优势。在Hibernate Native SQL Query Example阅读更多内容。

二十八、在Hibernate中原生SQL查询的支持有何好处?

当我们想要执行Hibernate API不支持的数据库特定查询时,原生SQL查询会派上用场,例如Oracle数据库中的查询提示或CONNECT关键字。

二十九、命名SQL查询是什么?

Hibernate提供了命名查询,我们可以在中央位置定义它们,并在代码中的任何地方使用它们。我们可以为HQL和原生SQL创建命名查询。Hibernate命名查询可以在Hibernate映射文件中定义,或者通过使用JPA注解@NamedQuery和@NamedNativeQuery来定义。

三十、命名 SQL 查询有哪些好处?

Hibernate命名查询帮助我们将查询分组在中央位置,而不是让它们散布在整个代码中。Hibernate命名查询语法在创建hibernate会话工厂时被检查,从而使应用程序在命名查询中有任何错误时快速失败。Hibernate命名查询是全局的,意味着一旦定义,它可以在整个应用程序中使用。然而,命名查询的一个主要缺点是它很难调试,因为我们需要找出它定义的位置。

三十一、Hibernate Criteria API 的好处是什么?

Hibernate提供了Criteria API,它更加面向对象,用于查询数据库和获取结果。我们不能使用Criteria来运行更新或删除查询或任何DDL语句。它仅用于使用更加面向对象的方法从数据库获取结果。Criteria API的一些常见用法是:

  • Criteria API提供了Projection,我们可以将其用于聚合函数,如sum()、min()、max()等。
  • Criteria API可以与ProjectionList一起使用,仅获取选定的列。
  • Criteria API可以通过连接多个表用于连接查询,有用的方法是createAlias()、setFetchMode()和setProjection()。
  • Criteria API可以用于获取带有条件的结果,有用的方法是add(),我们可以在其中添加Restrictions。
  • Criteria API提供了addOrder()方法,我们可以用它来对结果进行排序。

Hibernate Criteria Example学习一些快速示例。

三十二、如何将Hibernate生成的SQL查询记录在日志文件中?

我们可以为hibernate配置设置以下属性来记录SQL查询。

<property name="hibernate.show_sql">true</property>

但是我们应该只在开发或测试环境中使用它,并在生产环境中关闭它。

三十三、什么是Hibernate代理,它如何帮助实现延迟加载?

Hibernate使用代理对象来支持延迟加载。基本上,当你从表加载数据时,hibernate不会加载所有映射的对象。一旦你通过getter方法引用子对象或查找对象,如果链接的实体不在会话缓存中,那么代理代码将转到数据库并加载链接的对象。它使用javassist来有效地和动态地生成实体对象的子类实现。

三十四、如何在Hibernate中实现关联关系?

我们可以轻松地在hibernate中实现一对一、一对多和多对多关系。这可以通过使用JPA注解以及基于XML的配置来完成。为了更好地理解,您应该阅读以下教程。

  1. Hibernate一对一映射
  2. Hibernate一对多映射
  3. Hibernate多对多映射

三十五、Hibernate中的事务管理是如何工作的?

事务管理在hibernate中非常容易,因为大多数操作不允许在事务外执行。所以从SessionFactory获取会话后,我们可以调用sessionbeginTransaction()来启动事务。此方法返回Transaction引用,我们稍后可以使用它来提交或回滚事务。总的来说,hibernate事务管理比JDBC事务管理更好,因为我们不需要依赖异常来回滚。会话方法抛出的任何异常都会自动回滚事务。

三十六、什么是级联,有哪些不同类型的级联?

当实体之间存在关系时,我们需要定义不同的操作将如何影响其他实体。这是通过级联完成的,并且有不同类型的级联。以下是在主实体和辅助实体之间应用级联的简单示例。

import org.hibernate.annotations.Cascade;

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

@OneToOne(mappedBy = "employee")
@Cascade(value = org.hibernate.annotations.CascadeType.ALL)
private Address address;

}

请注意,Hibernate CascadeType枚举常量与JPAjavax.persistence.CascadeType略有不同,所以我们需要使用Hibernate CascadeType和Cascade注解进行映射,如上例所示。CascadeType枚举中定义的常用级联类型有:

  1. None:没有级联,它不是一个类型,但当我们不定义任何级联时,父级中的任何操作都不会影响子级。
  2. ALL:级联保存、删除、更新、驱逐、锁定、复制、合并、持久化。基本上是一切。
  3. SAVE_UPDATE:级联保存和更新,仅在hibernate中可用。
  4. DELETE:对应于Hibernate原生DELETE操作,仅在hibernate中可用。
  5. DETATCH, MERGE, PERSIST, REFRESH和REMOVE – 用于类似操作。
  6. LOCK:对应于Hibernate原生LOCK操作。
  7. REPLICATE:对应于Hibernate原生REPLICATE操作。

三十七、如何在Hibernate应用程序中集成log4j日志记录?

Hibernate 4使用JBoss日志记录,而不是早期版本中使用的slf4j。对于log4j配置,我们需要遵循以下步骤。

  • 为maven项目添加log4j依赖项,如果不是maven,则添加相应的jar文件。
  • 创建log4j.xml配置文件或log4j.properties文件,并将其保留在类路径中。您可以将文件名保留为您想要的任何名称,因为我们将在下一步中加载它。
  • 对于独立项目,使用静态块通过DOMConfiguratorPropertyConfigurator配置log4j。对于Web应用程序,您可以使用ServletContextListener来配置它。

就是这样,我们的设置准备好了。在java类中创建org.apache.log4j.Logger实例并开始日志记录。对于完整的示例代码,您应该阅读Hibernate log4j exampleServlet log4j example

三十八、如何在Hibernate框架中使用应用程序服务器的JNDI数据源?

对于Web应用程序,最好让servlet容器管理连接池。这就是为什么我们为DataSource定义JNDI资源,我们可以在Web应用程序中使用它。在Hibernate中使用它非常容易,我们所需要做的就是删除所有特定于数据库的属性,并使用以下属性来提供JNDI DataSource名称。

<property name="hibernate.connection.datasource">java:comp/env/jdbc/MyLocalDB</property>

对于完整示例,请阅读Hibernate JNDI DataSource Example

三十九、如何将Hibernate和Spring框架集成?

Spring是最常用的Java EE框架之一,Hibernate是最流行的ORM框架。这就是为什么Spring Hibernate组合在企业应用程序中被大量使用。使用Spring的最佳部分是它通过Spring ORM模块提供了对Hibernate的开箱即用集成支持。将Spring和Hibernate框架集成在一起需要以下步骤。

  1. 添加hibernate-entitymanager、hibernate-core和spring-orm依赖项。
  2. 为数据库操作创建模型类和相应的DAO实现。注意DAO类将使用SessionFactory,它将由Spring Bean配置注入。
  3. 如果您使用Hibernate 3,您需要在Spring Bean配置文件中配置org.springframework.orm.hibernate3.LocalSessionFactoryBeanorg.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean。对于Hibernate 4,有一个单一的类org.springframework.orm.hibernate4.LocalSessionFactoryBean应该被配置。
  4. 注意,我们不需要使用Hibernate事务管理,我们可以将其留给Spring使用@Transactional注解的声明式事务管理。

对于完整示例,请阅读Spring Hibernate IntegrationSpring MVC Hibernate Integration

四十、什么是HibernateTemplate类?

当Spring和Hibernate集成开始时,Spring ORM提供了两个辅助类——HibernateDaoSupportHibernateTemplate。使用它们的原因是从Hibernate获取Session并获得Spring事务管理的好处。然而从Hibernate 3.0.1开始,我们可以使用SessionFactory的getCurrentSession()方法来获取当前会话,并使用它来获取spring事务管理的好处。如果您阅读上述示例,您将看到它多么容易,这就是为什么我们不应该再使用这些类。HibernateTemplate的另一个好处是异常转换,但这可以通过在服务类中使用@Repository注解轻松实现,如上面的spring mvc示例所示。这是一个判断您的知识以及您是否了解最新发展的技巧问题。

四十一、如何将Hibernate与Servlet或Struts2 Web应用程序集成在一起?

Hibernate与Servlet或Struts2的集成需要使用ServletContextListener完成,完整示例可以在Hibernate Struts2 Integration Example中找到。

四十二、Hibernate框架中使用了哪些设计模式?

Hibernate框架中使用的一些设计模式有:

  • 域模型模式(Domain Model Pattern) – 一个包含行为和数据的域对象模型。
  • 数据映射器(Data Mapper) – 一层映射器,在对象和数据库之间移动数据,同时保持它们彼此独立以及映射器本身独立。
  • 用于延迟加载的代理模式(Proxy Pattern)
  • SessionFactory中的工厂模式(Factory pattern)

四十三、跟随Hibernate框架需要遵循哪些最佳实践?

在Hibernate中需要遵循的一些最佳实践是:

  • 始终检查主键字段访问,如果它是在数据库层生成的,那么您不应该为此设置setter。
  • 默认情况下,hibernate直接设置字段值,而不使用setter。所以如果您希望hibernate使用setter,那么确保定义了适当的访问,如@Access(value=AccessType.PROPERTY)
  • 如果访问类型是property,确保注解与getter方法一起使用,而不是setter方法。避免在字段和getter方法上混合使用注解。
  • 只有在无法使用HQL时才使用原生sql查询,例如使用数据库特定功能。
  • 如果必须对集合进行排序,请使用有序列表而不是使用Collection API对其进行排序。
  • 明智地使用命名查询,将其保存在一个地方以便于调试。仅对常用查询使用它们。对于实体特定查询,您可以将其保留在实体bean本身中。
  • 对于Web应用程序,始终尝试使用JNDI DataSource,而不是在hibernate中配置创建连接。
  • 避免多对多关系,它可以很容易地使用双向一对多和多对一关系来实现。
  • 对于集合,尽量使用Lists、maps和sets。避免使用数组,因为您无法获得延迟加载的好处。
  • 不要将异常视为可恢复的,回滚事务并关闭会话。如果您不这样做,Hibernate无法保证内存状态准确表示持久状态。
  • 对于可以与实体bean一起使用的不同方法,优先使用DAO模式。
  • 对于关联,优先使用延迟获取。

四十四、Hibernate验证器框架是什么?

数据验证是任何应用程序不可或缺的部分。您将在表示层找到数据验证,使用Javascript,然后在处理之前在服务器端代码中。数据验证也在持久化之前发生,以确保它遵循正确的格式。验证是一个横切任务,所以我们应该尽量将其与业务逻辑分开。这就是为什么JSR303和JSR349提供了通过使用注解来验证bean的规范。Hibernate Validator提供了这两个bean验证规范的参考实现。在Hibernate Validation Example阅读更多内容。

四十五、Hibernate Tools Eclipse插件有什么好处?

Hibernate Tools插件帮助我们轻松编写hibernate配置和映射文件。主要好处是内容辅助,帮助我们使用属性或xml标签。它还根据Hibernate DTD文件验证它们,所以我们提前知道任何错误。在Hibernate Tools Eclipse Plugin学习如何安装和使用。

关于Hibernate面试问题和答案就这些,我希望它对你作为应聘者或经验丰富者的面试有所帮助。如果我遗漏了任何重要的问题,请告诉我,我会将其添加到列表中。

bannerAds