做写字楼的网站有哪些,wordpress 360cdn,中国企业集成网网址,专业英文网站建设了解如何使用Hibernate轻松解决最常见的问题 Hibernate可能是市场上最受欢迎的JPA实现#xff0c;您可以在许多地方看到它#xff0c;例如#xff1a; 您自己使用过的项目数#xff0c; 需要Hibernate经验的职位数量#xff0c;当然还有 互联网上发布的问题和例外数量… 了解如何使用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);
HashMapString, 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上调用getEntityGraphString name方法以获取实体图的实例。 在下一步中我将创建带有查询提示的HashMap并将该图添加为javax.persistence.fetchgraph。 在最后一步中我将查询提示作为find方法的附加参数。 这告诉Hibernate初始化与Book实体的关系并且我可以在没有活动的Hibernate会话的情况下调用getBooks方法。 2. OptimisticLockException 另一个非常常见的异常是OptimisticLockException。 当您使用乐观锁定并检测到实体的更新冲突时Hibernate会抛出该错误。 发生这种情况最常见的原因有两个 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分离的实体传递给持久化 此列表中的最后一个异常可能有多种原因并且都是错误 您尝试保留一个新实体并提供主键值但是实体映射定义了一种生成它的策略。 您尝试保留一个新实体并且持久性上下文已经包含具有给定ID的实体。 您尝试保留一个分离的实体而不是合并它。 第一个很容易修复不提供主键值或删除主键生成策略。 仅当您自己管理主键值并且您的算法创建重复项时才会发生第二种情况。 解决此问题的首选方法是让Hibernate使用数据库序列生成主键值而不是实现自己的算法。 这并非总是可能的在这种情况下您必须测试和调试用于生成主键值的算法。 根据算法的不同这可能是一项繁琐且耗时的任务。 第三种经常发生在您在客户端中使用实体时客户端调用了错误的服务器方法该方法将保留新实体而不是更新现有实体。 解决此错误的明显方法是修复客户端中的呼叫。 另外您可以在服务器端执行某些操作来避免此类问题例如使用特定的值对象创建用例而不是在同一服务器方法中处理创建和更新用例。 这使客户开发人员更容易找到并调用正确的方法并避免了此类问题。 摘要和备忘单 这些是我最常遇到的5个Hibernate Exception以及如何修复它们。 如您所见异常及其原因非常不同。 其中一些仅在开发期间发生而另一些会在生产中对您造成打击。 因此最好提防并确保您熟悉这些问题。 为了让您更轻松我准备了一份备忘单解释了本文中提到的5个例外 。 翻译自: https://www.javacodegeeks.com/2016/06/5-common-hibernate-exceptions-fix.html