有没有办法在自由应用服务器上捕获org.hibernate.exception.ConstraintViolationException?
我有一个存储库代码:
@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) {
}
}
} 我总是收到这样的例外:
[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配置:
<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> 所以,我想忽略这个例外,但仍然收到!
如何解决这个问题?
发布于 2021-11-16 21:17:48
这个异常在使用普通JDBC时可以通过SQLIntegrityConstraintViolationException来捕获,但是在使用JPA时不能这样做,因为它不应该是业务逻辑的一部分(相同的SQLIntegrityConstraintViolationException将被多次包装在不同的JPA数据异常中)。这种例外不是你想要抓住的,而是要防止的。它通常表明您的业务逻辑中存在误解。我的建议是分析为什么会发生这种情况,并重构您的逻辑以避免它,它很可能会导致更健壮的代码。
如果你想进一步解释你的商业案例,我可以给你一个具体的建议。但只是为了提供一些东西:
您可以使用查询检查是否存在带约束的数据。如果不这样做,就会产生一个NoResultException (这是一个异常,可以是业务逻辑的一部分)。它讨论的是数据,而不是SQL内容),在catch块中,您现在可以安全地执行插入。
另一个问题是,如果这个选择可以同时发生在两个不同的事务中。在这种情况下,您需要微调表示ISOLATION_LEVEL的连接。但这将是另一个不同的问题。
代码的非主题推荐()
UserTransaction:至少在您正在使用的示例中,您不需要这样做。所有会话Bean (也称为EJB) (即无状态、状态和Singleton)默认提供事务处理。这意味着在任何业务方法之前,一个新的事务将自动启动,并在方法的末尾提交它。如果方法抛出异常,事务将自动回滚。
如果业务方法是从另一个EJB调用的,那么它将重用相同的事务。
这是默认行为,而且非常强大,允许在不手动管理事务的情况下管理大部分业务用例。
发布于 2021-09-29 21:07:46
如果您使用em.merge(market);而不是em.persist(market);,JPA会将其转换为insert-如果没有-否则-更新,这将避免违反数据库中的约束,即每个(交换,符号)配对都是唯一的。
如果唯一约束不是主键,则这可能无法工作。或者即使是..。我的经验是,您无法捕捉持久性容器抛出的异常。一种解决方案是确保不存在具有相同交换和符号的记录:
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();
}https://stackoverflow.com/questions/69342894
复制相似问题