2023年最新Hibernate面试题及答案大全(含详细解析)
这是文章《Hibernate面试问题和答案》的第1部分(共2部分)。
Hibernate是Java应用程序中最广泛使用的ORM(对象关系映射)工具之一。在企业应用程序中,它在数据库操作中被大量使用。因此,在面试之前,我决定写一篇关于Hibernate面试问题的文章,以便帮助你巩固知识。无论你是刚入行还是经验丰富,掌握Hibernate ORM工具的知识都有助于你在面试中取得好成绩。在这里,我提供了一些重要的Hibernate面试问题及答案,帮助你巩固知识并给面试官留下深刻印象。就像其他面试问题文章一样,我可能会在将来添加更多问题到这个列表中,所以你可能想要将其添加到书签中以备将来参考。最近,我已经写了很多关于Hibernate的文章,其中大部分都包含完整的可下载项目。在需要时,我会提供相关参考,并请你查阅以更新知识。
Hibernate面试问题
- Hibernate框架是什么?
- Java持久化API(JPA)是什么?
- 使用Hibernate框架的重要优势有哪些?
- Hibernate相比JDBC的优势是什么?
- Hibernate框架的一些重要接口是什么?
- Hibernate配置文件是什么?
- Hibernate映射文件是什么?
- 用于Hibernate映射的一些重要注解是什么?
- Hibernate SessionFactory是什么,如何配置它?
- Hibernate SessionFactory是线程安全的吗?
- Hibernate Session是什么,如何获得它?
- Hibernate Session是线程安全的吗?
- openSession和getCurrentSession有什么区别?
- Hibernate Session的get()和load()方法有什么区别?
- Hibernate缓存是什么?解释Hibernate一级缓存是什么?
- 如何使用EHCache配置Hibernate二级缓存?
- 实体Bean的不同状态有哪些?
- Hibernate Session merge()方法有什么用?
- Hibernate的save()、saveOrUpdate()和persist()方法有什么区别?
- 如果实体Bean没有无参数构造函数会发生什么?
- 有序集合和无序集合有什么区别,哪个更好?
- Hibernate中有哪些集合类型?
- 如何在Hibernate中实现连接查询?
- 为什么我们不应该将实体类设为final?
- HQL是什么,它的好处是什么?
- Hibernate中的查询缓存是什么?
- 我们可以在Hibernate中执行原生SQL查询吗?
- Hibernate支持原生SQL查询有什么好处?
- 什么是命名SQL查询?
- 命名SQL查询的好处是什么?
- Hibernate Criteria API的好处是什么?
- 如何在日志文件中记录Hibernate生成的SQL查询?
- Hibernate代理是什么,它如何帮助实现延迟加载?
- 如何在Hibernate中实现关系型数据库?
- Hibernate中事务管理是如何工作的?
- 什么是级联,有哪些不同类型的级联?
- 如何在Hibernate应用中集成log4j日志记录?
- 如何在Hibernate框架中使用应用程序服务器JNDI DataSource?
- 如何将Hibernate与Spring框架集成?
- HibernateTemplate类是什么?
- 如何在Servlet或Struts2 web应用程序中集成Hibernate?
- Hibernate框架使用了哪些设计模式?
- 在Hibernate框架中应该遵循哪些最佳实践?
- Hibernate验证器框架是什么?
- 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框架的一些重要接口包括:
- SessionFactory (org.hibernate.SessionFactory):SessionFactory是一个不可变的线程安全的编译映射缓存,用于单个数据库。我们需要初始化SessionFactory一次,然后我们可以缓存并重用它。SessionFactory实例用于获取用于数据库操作的Session对象。
- Session (org.hibernate.Session):Session是一个单线程的、短生命周期的对象,表示应用程序和持久存储之间的对话。它包装了JDBC的
java.sql.Connection
,并作为org.hibernate.Transaction
的工厂工作。我们应该只在需要时打开session,并在使用完毕后立即关闭它。Session对象是java应用程序代码和hibernate框架之间的接口,并提供CRUD操作的方法。 - 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注解包括:
- javax.persistence.Entity:与模型类一起使用,以指定它们是实体bean。
- javax.persistence.Table:与实体bean一起使用,以定义数据库中相应的表名。
- javax.persistence.Access:用于定义访问类型,可以是字段或属性。默认值是字段,如果您希望hibernate使用getter/setter方法,则需要将其设置为property。
- javax.persistence.Id:用于定义实体bean中的主键。
- javax.persistence.EmbeddedId:用于定义实体bean中的复合主键。
- javax.persistence.Column:用于定义数据库表中的列名。
- javax.persistence.GeneratedValue:用于定义用于生成主键的策略。与
javax.persistence.GenerationType
枚举一起使用。 - javax.persistence.OneToOne:用于定义两个实体bean之间的一对一映射。我们有其他类似的注解,如
OneToMany
、ManyToOne
和ManyToMany
。 - org.hibernate.annotations.Cascade:用于定义两个实体bean之间的级联,与映射一起使用。它与
org.hibernate.annotations.CascadeType
一起工作。 - javax.persistence.PrimaryKeyJoinColumn:用于定义外键的属性。与
org.hibernate.annotations.GenericGenerator
和org.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是最常用的方法,乍一看它们似乎相似,但它们之间有一些区别。
- get()在调用时立即加载数据,而load()返回一个代理对象,并且只在实际需要时加载数据,所以load()更好,因为它支持延迟加载。
- 由于load()在找不到数据时抛出异常,我们应该只在确定数据存在时使用它。
- 当我们想要确保数据存在于数据库中时,应该使用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实例可以存在于三种状态之一。
- 瞬时态(Transient):当一个对象从未被持久化或与任何会话关联时,它处于瞬时态。可以通过调用save()、persist()或saveOrUpdate()使瞬时实例变为持久态。可以通过调用delete()使持久实例变为瞬时态。
- 持久态(Persistent):当一个对象与唯一的会话关联时,它处于持久态。任何由get()或load()方法返回的实例都是持久态的。
- 游离态(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应该实现Comparable
或Comparator
接口才能工作,在java对象列表排序阅读更多内容。如果我们使用Hibernate框架从数据库加载集合数据,我们可以使用它的Criteria API来使用”order by”子句来获取有序列表。下面的代码片段向您展示了如何获取它。
List<Employee> empList = session.createCriteria(Employee.class)
.addOrder(Order.desc("id")).list();
有序列表比排序列表更好,因为实际的排序是在数据库级别完成的,这很快并且不会导致内存问题。
二十二、在Hibernate中有哪些收集类型?
hibernate中有五种集合类型用于一对多关系映射。
- Bag(包)
- Set(集)
- List(列表)
- Array(数组)
- 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的配置来完成。为了更好地理解,您应该阅读以下教程。
三十五、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枚举中定义的常用级联类型有:
- None:没有级联,它不是一个类型,但当我们不定义任何级联时,父级中的任何操作都不会影响子级。
- ALL:级联保存、删除、更新、驱逐、锁定、复制、合并、持久化。基本上是一切。
- SAVE_UPDATE:级联保存和更新,仅在hibernate中可用。
- DELETE:对应于Hibernate原生DELETE操作,仅在hibernate中可用。
- DETATCH, MERGE, PERSIST, REFRESH和REMOVE – 用于类似操作。
- LOCK:对应于Hibernate原生LOCK操作。
- REPLICATE:对应于Hibernate原生REPLICATE操作。
三十七、如何在Hibernate应用程序中集成log4j日志记录?
Hibernate 4使用JBoss日志记录,而不是早期版本中使用的slf4j。对于log4j配置,我们需要遵循以下步骤。
- 为maven项目添加log4j依赖项,如果不是maven,则添加相应的jar文件。
- 创建log4j.xml配置文件或log4j.properties文件,并将其保留在类路径中。您可以将文件名保留为您想要的任何名称,因为我们将在下一步中加载它。
- 对于独立项目,使用静态块通过
DOMConfigurator
或PropertyConfigurator
配置log4j。对于Web应用程序,您可以使用ServletContextListener来配置它。
就是这样,我们的设置准备好了。在java类中创建org.apache.log4j.Logger
实例并开始日志记录。对于完整的示例代码,您应该阅读Hibernate log4j example和Servlet 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框架集成在一起需要以下步骤。
- 添加hibernate-entitymanager、hibernate-core和spring-orm依赖项。
- 为数据库操作创建模型类和相应的DAO实现。注意DAO类将使用SessionFactory,它将由Spring Bean配置注入。
- 如果您使用Hibernate 3,您需要在Spring Bean配置文件中配置
org.springframework.orm.hibernate3.LocalSessionFactoryBean
或org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
。对于Hibernate 4,有一个单一的类org.springframework.orm.hibernate4.LocalSessionFactoryBean
应该被配置。 - 注意,我们不需要使用Hibernate事务管理,我们可以将其留给Spring使用
@Transactional
注解的声明式事务管理。
对于完整示例,请阅读Spring Hibernate Integration和Spring MVC Hibernate Integration。
四十、什么是HibernateTemplate类?
当Spring和Hibernate集成开始时,Spring ORM提供了两个辅助类——HibernateDaoSupport
和HibernateTemplate
。使用它们的原因是从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面试问题和答案就这些,我希望它对你作为应聘者或经验丰富者的面试有所帮助。如果我遗漏了任何重要的问题,请告诉我,我会将其添加到列表中。