首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >自由JavaEE 8捕捉ConstraintViolationException

自由JavaEE 8捕捉ConstraintViolationException
EN

Stack Overflow用户
提问于 2021-09-27 07:43:01
回答 2查看 168关注 0票数 0

有没有办法在自由应用服务器上捕获org.hibernate.exception.ConstraintViolationException

我有一个存储库代码:

代码语言:javascript
复制
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class MarketRepository {

    @PersistenceContext
    private EntityManager em;

    @Resource
    private UserTransaction tx;

    public void insert(Market market) {
        try {
            tx.begin();
            em.persist(market);
            tx.commit();
        } catch (Exception ignore) {
        }
    }
}     

我总是收到这样的例外:

代码语言:javascript
复制
[INFO] Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
[INFO]  at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:109)
[INFO]  at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
[INFO]  at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
[INFO]  at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
[INFO]  at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)
[INFO]  at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3238)
[INFO]  at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3763)
[INFO]  at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:107)
[INFO]  at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
[INFO]  at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
[INFO]  at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:723)
[INFO]  at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
[INFO]  at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)
[INFO]  at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)
[INFO]  at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102)
[INFO]  at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1360)
[INFO]  ... 20 more
[INFO] Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "ukmn9r4yewa9epwp1ekfsbm69gu"
[INFO]   Detail: Key (exchange, symbol)=(COINEX, ZECUSDT) already exists.
[INFO]  at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2533)
[INFO]  at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2268)
[INFO]  at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:313)
[INFO]  at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:448)
[INFO]  at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:369)
[INFO]  at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:159)
[INFO]  at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:125)
[INFO]  at jdk.internal.reflect.GeneratedMethodAccessor1090.invoke(Unknown Source)
[INFO]  at java.base/java.lang.reflect.Method.invoke(Method.java:567)
[INFO]  at org.postgresql.ds.PGPooledConnection$StatementHandler.invoke(PGPooledConnection.java:428)
[INFO]  at jdk.proxy11/jdk.proxy11.$Proxy136.executeUpdate(Unknown Source)
[INFO]  at com.ibm.ws.rsadapter.jdbc.WSJdbcPreparedStatement.executeUpdate(WSJdbcPreparedStatement.java:520)
[INFO]  at [internal classes]
[INFO]  at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
[INFO]  ... 31 more

这是我的server.xml配置:

代码语言:javascript
复制
 <dataSource jndiName="jdbc/jta-datasource" transactional="true">
        <jdbcDriver id="database-driver" libraryRef="project-libs"/>
        <properties databaseName="${database.name}" serverName="${database.hostname}" portNumber="${database.port}"
                    user="${database.username}" password="${database.password}"/>
    </dataSource>    

所以,我想忽略这个例外,但仍然收到!

如何解决这个问题?

EN

回答 2

Stack Overflow用户

发布于 2021-11-16 21:17:48

这个异常在使用普通JDBC时可以通过SQLIntegrityConstraintViolationException来捕获,但是在使用JPA时不能这样做,因为它不应该是业务逻辑的一部分(相同的SQLIntegrityConstraintViolationException将被多次包装在不同的JPA数据异常中)。这种例外不是你想要抓住的,而是要防止的。它通常表明您的业务逻辑中存在误解。我的建议是分析为什么会发生这种情况,并重构您的逻辑以避免它,它很可能会导致更健壮的代码。

如果你想进一步解释你的商业案例,我可以给你一个具体的建议。但只是为了提供一些东西:

您可以使用查询检查是否存在带约束的数据。如果不这样做,就会产生一个NoResultException (这是一个异常,可以是业务逻辑的一部分)。它讨论的是数据,而不是SQL内容),在catch块中,您现在可以安全地执行插入。

另一个问题是,如果这个选择可以同时发生在两个不同的事务中。在这种情况下,您需要微调表示ISOLATION_LEVEL的连接。但这将是另一个不同的问题。

代码的非主题推荐()

UserTransaction:至少在您正在使用的示例中,您不需要这样做。所有会话Bean (也称为EJB) (即无状态、状态和Singleton)默认提供事务处理。这意味着在任何业务方法之前,一个新的事务将自动启动,并在方法的末尾提交它。如果方法抛出异常,事务将自动回滚。

如果业务方法是从另一个EJB调用的,那么它将重用相同的事务。

这是默认行为,而且非常强大,允许在不手动管理事务的情况下管理大部分业务用例。

票数 1
EN

Stack Overflow用户

发布于 2021-09-29 21:07:46

如果您使用em.merge(market);而不是em.persist(market);,JPA会将其转换为insert-如果没有-否则-更新,这将避免违反数据库中的约束,即每个(交换,符号)配对都是唯一的。

如果唯一约束不是主键,则这可能无法工作。或者即使是..。我的经验是,您无法捕捉持久性容器抛出的异常。一种解决方案是确保不存在具有相同交换和符号的记录:

代码语言:javascript
复制
String jpql = "select count(*) from Market where m.exchange = ? and m.symbol = ?";
tx.begin();
int count = em.createQuery(jpql, Integer.class)
.setParameter(1, market.getExchange())
.setParameter(2, market.getSymbol()).getSingleResult();
if(count == 0){
  em.persist(market);
  tx.commit();
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69342894

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档