我正在使用Primefaces进行一个Web项目,该项目从使用JPA的远程EJB发送和获取数据。在实体Bean中设置unique=true
后,我得到了这段代码来处理唯一值:
try{
emsave.persist(newItem);
} catch (PersistenceException pe){
System.out.println("dupe found");
}
然后我回滚了这个交易。 在Eclipse控制台中,我从Jboss AS获得这些消息:
09:15:12,179 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-localhost-127.0.0.1-8189-6) SQL Error: 1062, SQLState: 23000
09:15:12,179 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-localhost-127.0.0.1-8189-6) Duplicate entry 'asdasd' for key 'username'
我必须将无法保存的对象发送回前端并将其显示在表格中,或者在表格中以某种方式标记它们,以便用户知道他必须更改的内容。我有办法怎么做,但我不知道如何标记哪个字段有坏的价值。是否有可能从此异常中错误地填充“用户名”字段,或者应该使用其他方式?我正在寻找最优雅的解决方案。
答案 0 :(得分:2)
首先,persist()
不会引发异常。 persist()
仅通过将对象附加到持久性上下文来将对象标记为持久性。实际插入将在冲洗时发生。
其次,似乎你想在循环中这样做。所有运行时延迟都是不可恢复的,并使上下文处于不可靠状态。一旦出现异常,就应该回滚当前事务,并且不应该继续使用实体管理器。
最后,这两个事实和常见的良好实践导致了解决方案:您不应该依赖异常来检测错误的值。如果名称应该是唯一的,那么您应该发出一个查询来测试表中是否已存在输入的名称,并且只有在验证了所有内容后才插入。当然,您可能在两个并发事务之间存在竞争条件,但这种情况不会经常发生,因此您可以使用通用的“Oops”错误消息来处理它(或者如果确实需要,则重试事务)。
答案 1 :(得分:1)
没有好办法做到这一点。问题是JPA不验证数据库约束本身。它只是将此检查委托给底层数据库。因此,JDBC驱动程序抛出具体异常,并由PersistenceException
包装。你可以显然调用pe.getCause()
(甚至可能两次 - 看看使用调试器抛出了什么样的异常)并尝试处理异常消息。但请注意,这可能取决于底层数据库和/或其JDBC驱动程序。
但是:通常,创建基于异常的流程是一种非常糟糕的做法。您应该自己验证应用程序级别“约束”,如果可能出现唯一约束违规,则不要尝试执行操作。无论如何它都发生了无关:用户应该尝试再次执行操作。用户不应该执行“错误”操作:UI应该保护他。