5个常见的Hibernate异常及其解决方法

了解如何使用Hibernate轻松解决最常见的问题

Hibernate可能是市场上最受欢迎的JPA实现,您可以在许多地方看到它,例如:

  • 您自己使用过的项目数,
  • 需要Hibernate经验的职位数量,当然还有
  • 互联网上发布的问题和例外数量

在Takipi,重点是查找和修复异常。 因此,我将重点关注列表中的最后一点,并与您分享我可能已经解决,解释,写博客和抱怨的5个Hibernate异常,这是我与Hibernate合作超过15年以来最多的。

尽管他们并没有为十大例外类型提供支持 ,但谷歌的快速搜索告诉我,我并不是唯一面对这些问题的人。

但是在我们探讨不同的例外之前,这篇文章是一篇很长的文章,我在免费备忘单中总结了最重要的观点。 您可以在这篇文章的末尾下载它。

1. LazyInitializationException

如果您尝试在没有活动会话的情况下尝试访问另一个实体的未初始化关系,则Hibernate会抛出LazyInitializationException。 您可以在以下代码片段中看到一个简单的示例。

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();Author a = em.find(Author.class, 1L);em.getTransaction().commit();
em.close();log.info(a.getFirstName() + " " + a.getLastName() + " wrote "+a.getBooks().size() + " books.");

好的,您现在可能会说您永远不会那样做。 尽管您可能永远不会在应用程序中使用完全相同的代码是正确的,但您可以无意间轻松地执行相同的操作。

最受欢迎的方法是在您的业务层中未初始化的演示层中访问与FetchType.LAZY的关系。 您可以在受欢迎的论坛中找到很多此类问题,并提出了许多不良的解决方法。

请不要在视图反模式中使用打开的会话。 它造成的危害更大,然后才带来收益。

修复LazyInitializationException的最佳方法是在业务层中初始化所需的关系。 但是不要仅仅因为可能有一个客户需要其中之一就初始化所有关系。 出于性能原因,您应该只初始化所需的关系。

JPA和Hibernate提供了不同的选项来初始化延迟获取的关系 。 我个人最喜欢的是@NamedEntityGraph ,它提供了独立于查询的方式来定义将随查询获取的实体图。

您可以在以下代码段中看到一个简单图形的示例。 它获取一个Author实体的Book关系。

@NamedEntityGraph(name = "graph.AuthorBooks", attributeNodes = @NamedAttributeNode("books"))

您可以在Hibernate可用的任何文件中定义@NamedEntityGraph。 我更喜欢在打算与之一起使用的实体上进行操作。

如您所见,定义图形不需要做太多的事情。 您只需要提供名称和@NamedAttributeNode批注的数组即可定义Hibernate从数据库中获取的属性。 在此示例中,只有book属性将关系映射到Book实体。

然后,您可以提供此图作为Hibernate的提示,以定义应使用给定查询初始化的关系。 您可以在以下代码段中看到一个示例。

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();EntityGraph<?> graph = em.getEntityGraph("graph.AuthorBooks");
HashMap<String, Object> properties = new HashMap<>();
properties.put("javax.persistence.fetchgraph", graph);Author a = em.find(Author.class, 1L, properties);em.getTransaction().commit();
em.close();log.info(a.getFirstName() + " " + a.getLastName() + " wrote "+a.getBooks().size() + " books.");

如您所见,我首先在EntityManager上调用getEntityGraph(String name)方法以获取实体图的实例。 在下一步中,我将创建带有查询提示的HashMap并将该图添加为javax.persistence.fetchgraph。

在最后一步中,我将查询提示作为find方法的附加参数。 这告诉Hibernate初始化与Book实体的关系,并且我可以在没有活动的Hibernate会话的情况下调用getBooks()方法。

2. OptimisticLockException

另一个非常常见的异常是OptimisticLockException。 当您使用乐观锁定并检测到实体的更新冲突时,Hibernate会抛出该错误。 发生这种情况最常见的原因有两个:

  1. 2个用户尝试在几乎相同的时间点更新同一实体。
  2. 1个用户对同一实体执行了2次更新,并且您没有刷新客户端中的实体表示,因此第一次更新后版本值未更新。

在下面的代码片段中,您可以看到具有2个并发更新的测试用例。

// EntityManager and transaction 1
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();// EntityManager and transaction 2
EntityManager em2 = emf.createEntityManager();
em2.getTransaction().begin();// update 1
Author a = em.find(Author.class, 1L);
a.setFirstName("changed");// update 2
Author a2 = em2.find(Author.class, 1L);
a2.setFirstName("changed");// commit transaction 1
em.getTransaction().commit();
em.close();// commit transaction 2
try {em2.getTransaction().commit();Assert.fail();} catch (RollbackException e) {Assert.assertTrue(e.getCause() instanceof OptimisticLockException);log.info("2nd transaction failed with an OptimisticLockException");}em2.close();

如您所见,我使用两个独立的EntityManager,并使用它们两个启动事务,获取ID为1的Author实体,并更新名字属性。

在我尝试提交第二个事务并为该Author实体的并发更新进行Hibernate检查之前,该方法可以正常工作。 当然,在实际应用中,这将通过两次并行调用同一方法来完成。

如果使用Takipi ,则可以在发生异常时查看所有变量的状态,这对于识别第二个更新调用的来源很有用。

塔基皮回滚

Takipi的错误分析屏幕

在不引入悲观锁定的情况下,您无法做很多事情来避免这种异常,这会牺牲您的应用程序的性能。 只需尝试尽可能频繁地更新客户端中的实体表示,并保持更新操作越短越好。 那应该避免大多数不必要的OptimisticLockException,并且您需要在客户端应用程序中处理其余的剩余部分。

但是,如果只有一个用户自己导致OptimisticLockException,那么您会发现一个可以轻松修复的错误。 如果您使用乐观锁定,则Hibernate将使用version列来跟踪实体的当前版本并防止并发修改。 因此,您需要确保在用户触发实体上的任何更改后,客户端始终更新其对实体的表示。 而且,您的客户端应用程序也不应缓存实体或代表它的任何值对象。

3. org.hibernate.AnnotationException:未知的Id.generator

这是由错误的实体映射引起的,在开发过程中可能会遇到它。 原因很简单,您可以在@GeneratedValue批注中引用未知的序列生成器,如下面的代码片段所示。

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "authorSequence")
@Column(name = "id", updatable = false, nullable = false)
private Long id;

@GeneratedValue批注允许您定义主键值的生成策略。 在前面的代码片段中,我想使用数据库序列,并提供“ authorSequence”作为生成器的名称。

现在,许多开发人员期望“ authorSequence”将成为Hibernate将使用的数据库序列的名称。 事实并非如此。 这是@SequenceGenerator的名称,可用于提供有关Hibernate将使用的数据库序列的更多信息。

但是@SequenceGenerator的定义丢失了,因此Hibernate引发了AnnotationException。 要解决此问题,您必须像在以下代码片段中一样添加一个@SequenceGenerator批注。

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "authorSequence")
@SequenceGenerator(name = "authorSequence", sequenceName = "author_seq", initialValue = 1000)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

@SequenceGenerator批注允许您提供有关数据库序列以及Hibernate如何使用它的更多信息。 在此代码段中,我设置了序列的名称,即“ author_seq”,并将其初始值设置为1000。

您还可以指定序列所属的数据库模式以及Hibernate可以用于性能优化的分配大小。 您可以在以下文章中了解有关ID生成器的更多信息 。

4. QuerySyntaxException:表未映射

这是另一个典型的映射错误。 在大多数项目中,数据库架构已经存在或独立于您的实体映射定义。 那是一件好事。 请正确设计数据库模式,不要让Hibernate为您生成它!

如果您希望Hibernate在启动时设置数据库,最好提供一个SQL脚本,而不是让Hibernate根据您的实体映射生成数据库架构。

现在,回到QuerySyntaxException。 如果数据库模式是独立于您的实体定义的,则通常会遇到以下情况:默认表名与现有表的名称不匹配,或者该表是其他数据库模式的一部分。

在这种情况下,可以为架构和表名提供@Table批注,如以下代码片段所示。

@Entity
@Table(name = "author", schema = "bookstore")
public class Author implements Serializable {…
}

5. org.hibernate.PersistentObjectException:分离的实体传递给持久化

此列表中的最后一个异常可能有多种原因,并且都是错误:

  1. 您尝试保留一个新实体并提供主键值,但是实体映射定义了一种生成它的策略。
  2. 您尝试保留一个新实体,并且持久性上下文已经包含具有给定ID的实体。
  3. 您尝试保留一个分离的实体而不是合并它。

第一个很容易修复,不提供主键值或删除主键生成策略。

仅当您自己管理主键值并且您的算法创建重复项时,才会发生第二种情况。 解决此问题的首选方法是让Hibernate使用数据库序列生成主键值,而不是实现自己的算法。

这并非总是可能的,在这种情况下,您必须测试和调试用于生成主键值的算法。 根据算法的不同,这可能是一项繁琐且耗时的任务。

第三种经常发生在您在客户端中使用实体时,客户端调用了错误的服务器方法,该方法将保留新实体而不是更新现有实体。 解决此错误的明显方法是修复客户端中的呼叫。

另外,您可以在服务器端执行某些操作来避免此类问题,例如使用特定的值对象创建用例,而不是在同一服务器方法中处理创建和更新用例。 这使客户开发人员更容易找到并调用正确的方法,并避免了此类问题。

摘要和备忘单

这些是我最常遇到的5个Hibernate Exception,以及如何修复它们。 如您所见,异常及其原因非常不同。 其中一些仅在开发期间发生,而另一些会在生产中对您造成打击。 因此,最好提防并确保您熟悉这些问题。 为了让您更轻松,我准备了一份备忘单,解释了本文中提到的5个例外 。

翻译自: https://www.javacodegeeks.com/2016/06/5-common-hibernate-exceptions-fix.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/353767.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB figure中提取数据

MATLAB figure中提取数据 (2011-10-26 14:26:21) 转载▼标签&#xff1a; 杂谈 分类&#xff1a; matlab figure画出来&#xff0c;提取数据有很多好处&#xff0c;方便保存&#xff0c;计算&#xff0c;加工&#xff0c;还可以导入到origin里面画图。具体的方法就是两部。第一…

oracle客户端中文乱码问题的解决

1 查看服务器端编码 select userenv(language) from dual; 我实际查看到的结果为&#xff1a; USERENV(LANGUAGE) ----------------------------- AMERICAN_AMERICA.ZHS16GBK 2 执行语句 select * from V$NLS_PARAMETERS; 查看第一行PARAMETER项中为NLS_LANGUAGE对应的VALUE项…

avi文件格式详解

avi文件格式详解 AVI是音频视频交错(Audio Video Interleaved)的英文缩写&#xff0c;它是Microsoft公司开发的一种符合RIFF文件规范的数字音频与视频文件格式&#xff0c;原先用于Microsoft Video for Windows (简称VFW)环境&#xff0c;现在已被Windows 95/98、OS/2等多数操作…

并发编程---线程queue---进程池线程池---异部调用(回调机制)

线程 队列&#xff1a;先进先出堆栈&#xff1a;后进先出优先级&#xff1a;数字越小优先级越大&#xff0c;越先输出import queueq queue.Queue(3) # 先进先出-->队列q.put(first) q.put(2) # q.put(third) # q.put(4) #由于没有人取走&#xff0c;就会卡主 q.put(4,block…

SQL Server遗失管理权限账号密码怎么办?

假如一个SQL Server实例只允许“SQL身份认证”模式登录数据库&#xff0c;而糟糕的是你忘记了sa的密码&#xff08;sa出于安全考虑应该被禁用&#xff0c;这里仅仅为了描述问题&#xff09;或其它具有sysadmin角色的登录名的密码&#xff1f;个人就遇到这样一个案例&#xff0c…

MFC中Radio Button使用方法

MFC中Radio Button使用方法2012-04-19 09:44:22 我来说两句 收藏 我要投稿 先为对话框加上2个radio button&#xff0c;分别是Radio1和Radio2。 问题1&#xff1a;如何让Radio1或者Radio2默认选上&#xff1f;如何知道哪个被选上了&#xff1f; 关键是选上&#x…

hkws摄像头拆机

转载于:https://www.cnblogs.com/feipeng8848/p/8961924.html

java虚拟机常用命令工具

java虚拟机常用命令工具 博客分类&#xff1a; 虚拟机 虚拟机jvmjava 一、概述 程序运行中经常会遇到各种问题&#xff0c;定位问题时通常需要综合各种信息&#xff0c;如系统日志、堆dump文件、线程dump文件、GC日志等。通过虚拟机监控和诊断工具可以帮忙我们快速获取、分…

嵌入式基础篇 - 第2章 Systick系统定时器

2.1 STM32 的时钟系统 STM32 芯片为了实现低功耗&#xff0c;设计了一个功能完善但却非常复杂的时钟系统。普通的MCU 一般只要配置好 GPIO 的寄存器就可以使用了&#xff0c;但 STM32 还有一个步骤&#xff0c;就是开启外设时钟。 图2-1 STM32的时钟树在 STM32 中&#xff0c;…

kill所有java进程

kill所有java进程 ps -ef | grep java | grep -v grep |awk {print $2} | xargs -p kill -9如果不需要询问&#xff0c;把xargs后面 -p 参数去掉Aix 通过shell脚本kill杀指定进程&#xff0c;比如杀所有java进程 2012-11-16 15:31, Tags: 127人阅读----脚本杀进程-------------…

SpringAOP02 自定义注解

1 自定义注解 1.1 创建自定义注解 从java5开始就可以利用 interface 来定义自定义注解 技巧01&#xff1a;注解不能直接干扰程序代码的运行&#xff08;即&#xff1a;注解的增加和删除操作后&#xff0c;代码都可以正常运行&#xff09; 技巧02&#xff1a;Retention 用来声明…

您的框架有多可扩展性?

在参加会议时&#xff0c;我们总是会见到高素质的决策者&#xff0c;他们经常问同样的问题&#xff1a; 您的框架有多可扩展性&#xff1f;如果我需要比您开箱即用的功能更多的东西怎么办&#xff1f; 。 这个问题是非常合理的&#xff0c;因为他们只是不想被卡在开发曲线的中间…

python-面向对象编程设计与开发

编程范式 1、对不同类型的任务&#xff0c;所采取不同的解决问题的思路。 2、编程范式有两种 1、面向过程编程 2、面向对象编程 面向过程编程 什么是面向过程编程&#xff1f; 过程——解决问题的步骤 要解决一个大的问题 1、先把大问题拆分成若干小问题或子过程。 2、然后子过…

MFC下列表控件的使用

MFC下列表控件的使用 2012-11-09 16:46:57| 分类&#xff1a; 程序VC相关 | 标签&#xff1a; |字号大中小 订阅 1、应该加入头文件 #include <Atlbase.h>2、示例m_list.SetExtendedStyle(LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT|LVS_EX_ONECLICKACTIVATE);m_lis…

jbehave_使用JBehave,Gradle和Jenkins的行为驱动开发(BDD)

jbehave行为驱动开发 &#xff08;BDD&#xff09;是一个协作过程 &#xff0c;产品所有者&#xff0c;开发人员和测试人员可以合作交付可为业务带来价值的软件。 BDD是 测试驱动开发 &#xff08;TDD&#xff09; 的合理下一步 。 行为驱动的发展 本质上&#xff0c;BDD是一…

嵌入式 开发——DMA内存到外设

学习目标 加强理解DMA数据传输过程加强掌握DMA的初始化流程掌握DMA数据表查询理解源和目标的配置理解数据传输特点能够动态配置源数据学习内容 需求 串口发送数据 uint8_t data = 0x01; 串口发送(data); 实现串口的发送数据, 要求采用dma的方式 数据交互流程 CPU配置好DM…

XSS

1.什么是xss XSS攻击全称跨站脚本攻击&#xff0c;是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆&#xff0c;故将跨站脚本攻击缩写为XSS&#xff0c;XSS是一种在web应用中的计算机安全漏洞&#xff0c;它允许恶意web用户将代码植入到提供给其它用户使用的页面中…

Python之匿名函数

一、匿名函数&#xff1a;也叫lambda表达式 1.匿名函数的核心&#xff1a;一些简单的需要用函数去解决的问题&#xff0c;匿名函数的函数体只有一行 2.参数可以有多个&#xff0c;用逗号隔开 3.返回值和正常的函数一样可以是任意的数据类型 二、匿名函数练习 请把下面的函数转换…

vaadin_5分钟内Google App Engine上的Vaadin App

vaadin在本教程中&#xff0c;您将学习如何创建第一个Vaadin Web应用程序&#xff0c;如何在本地AppEngine开发服务器上运行它以及如何将其部署到Google App Engine基础结构。 所有这些大约需要5到10分钟。 是的&#xff0c;如果您已经安装了必要的先决条件&#xff0c;则可以立…

【分形】【洛谷P1498】

https://www.luogu.org/problemnew/show/P1498 题目描述 自从到了南蛮之地&#xff0c;孔明不仅把孟获收拾的服服帖帖&#xff0c;而且还发现了不少少数民族的智慧&#xff0c;他发现少数民族的图腾往往有着一种分形的效果&#xff0c;在得到了酋长的传授后&#xff0c;孔明掌握…