【问题标题】:Executing JPQL query in PersistenceException catch clause re-throws PersistenceException在 PersistenceException catch 子句中执行 JPQL 查询重新抛出 PersistenceException
【发布时间】:2017-07-03 11:24:14
【问题描述】:

我正在尝试使用 JPA 在我的 JavaEE 应用程序中的 DAO 中实现一些错误处理。

我遇到了某人(用户)可能尝试将重复项输入我的数据库的情况。我的计划是尝试坚持我的实体,例如。用户(“test@test.com”,“测试”,“密码”)。如果这失败并出现 PersistenceException 我想我可以检查唯一列上的重复条目,如用户名(“Test”)和电子邮件(“test@test.com)。如果我找到重复项,我想检查哪个它失败的列并相应地通知用户。

我的尝试如下:

getEntityManager().persist(entity);
try {
    getEntityManager().flush();
} catch (PersistenceException ex) {
    List<T> duplicates = findDuplicate(entity);
    if (duplicates.size() > 0) {
        // Notify user
    } else {
        // Probably pass exception forwards
    }
}

实体管理器被注入到类中:

@PersistenceContext(unitName = "RecruitmentPU")
protected EntityManager mEM;

getEntityManager() 只返回这个成员。它自己的类被注释为@Stateless。

要查找重复项,我基本上只是这样做:

String column = myEntity.getUniqueColumn(); // returns the name of the column
Object uniqueValue = myEntity.getUniqueValue(); // returns the value of the unique column

Query query = getEntityManager().createQuery(
        "SELECT e FROM TestEntity e WHERE " + column + " = :identifier",
        TestEntity.class
);

query.setParameter("identifier", uniqueValue);
List<T> entries = null;
try {
    entries = (List<T>) query.getResultList(); // Here the exception is re-thrown
} catch(Exception ex) {
    System.out.println("Caught something... \n" + ex.getMessage());
}

该实体还有一个 ID 列,其注释为 @GeneratedValue(strategy = GenerationType.IDENTITY)。还有一个@ManyToOne 属性在我简化代码时被删除。当我对此进行测试时,我得到以下输出:

Info:   Caught something... 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.3.qualifier): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'Test' for key 'username_UNIQUE'
Error Code: 1062
Call: INSERT INTO test.test (email, username, role) VALUES (?, ?, ?)
        bind => [3 parameters bound]
Query: InsertObjectQuery(ID: 0 | email: test@test.com | username: Test | password: ********)

目前我让容器处理事务,但我有预感我遇到了这些问题,因为我试图在第一个事务完成之前查询数据库(或类似的东西)。

是策略上的缺陷还是执行上的缺陷?我可以采取哪些步骤来开始解决这个问题?

【问题讨论】:

  • 神秘的getEntityManager()长什么样子?
  • 啊,这是注入成员的吸气剂。我将实体管理器注入@PersistenceContext(unitName = "RecruitmentPU") protected EntityManager mEM; 到同一个类(标记为@Stateless)。我已经用信息更新了问题。
  • 你如何在findDuplicate()中使用entity对象
  • 用户是否有一个额外的字段,称为ID,它是一个auto-invrement 字段?
  • 我使用实体来获取哪个列是唯一的,以及实体实例的该列的值,为问题添加了基础知识。是的,用户实体有一个自动生成的 ID 列,并且它还在简化示例中未显示的列上具有多对一关系。

标签: jpa jakarta-ee transactions persistence


【解决方案1】:

don't want 在发生异常后继续任何事务。

我建议你切换操作顺序,像这样:

  1. 查询数据库以获取唯一键等于您要保留的实体的唯一键的记录,
  2. 保留您的实体。

【讨论】:

  • 这可能是正确的答案,但这不会迫使我每次尝试向数据库添加内容时都要查询数据库两次吗?我希望通过尝试先插入然后检查可能发生这种情况的少数情况下出了什么问题来减少查询数量(基本上将数量减少一半)。有什么解决办法吗?
  • 那么只需persist()。异常会告诉你出了什么问题。
  • 这确实是一个可能的解决方案,并且可能我最终会这样做。但是,我玩了一下,使用EntityManager.clear() 怎么样?清除 PersistenceContext 似乎使我能够在 catch 子句中查询重复项。之后交易是烤面包,所以我将不得不丢弃它。但它似乎使我能够检查插入是否会在多列而不是一列上失败(这是异常告诉我的)。我是不是在做一些以后可能会回来咬我的事情?
  • 感谢您的耐心等待!我会看看是否有可能重新考虑并接受您的第一个建议,或者我会让交易失败并按照第二个建议处理异常。
猜你喜欢
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 2011-11-16
  • 1970-01-01
  • 2013-10-16
  • 1970-01-01
  • 2010-12-24
  • 1970-01-01
相关资源
最近更新 更多