代码之家  ›  专栏  ›  技术社区  ›  Sebastian S

getSingleResult()导致NoResultException回滚

  •  2
  • Sebastian S  · 技术社区  · 8 年前

    我在Wildfly 14上运行的应用程序中使用容器管理的事务。

    由于意外的事务回滚,以下代码失败:

    @Transactional
    public User example(...) {
        User user = findUserByName(...);
        // ...
    }
    
    private User findUserByName(String username) {
        try {
            User user = userDao.findUserByName(username); // throws NoResultException
            // ...
            return user;
        } catch (NoResultException e) {
            List<User> users = userDao.getAll(); // throws SQLException: Transaction cannot proceed: STATUS_MARKED_ROLLBACK
            // ...  
        }
    }
    

    正在阅读的JavaDoc NoResultException ,合同明确规定:

    如果当前事务处于活动状态,此异常不会导致标记为回滚。

    尽管如此,由于 getAll() (或任何其他查询)引发异常,其根本原因如下:

    Caused by: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not prepare statement
        at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
        at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
        at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1514)
        at org.hibernate.query.Query.getResultList(Query.java:135)
        at org.jboss.as.jpa.container.TypedQueryNonTxInvocationDetacher.getResultList(TypedQueryNonTxInvocationDetacher.java:58)
        at com.example.UserDao.getAll(UserDao.java:74)
        ... 64 more
    Caused by: org.hibernate.exception.GenericJDBCException: could not prepare statement
        at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
        at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
        at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:182)
        at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:148)
        at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1984)
        at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1914)
        at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1892)
        at org.hibernate.loader.Loader.doQuery(Loader.java:937)
        at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:340)
        at org.hibernate.loader.Loader.doList(Loader.java:2689)
        at org.hibernate.loader.Loader.doList(Loader.java:2672)
        at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2506)
        at org.hibernate.loader.Loader.list(Loader.java:2501)
        at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:504)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:395)
        at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:220)
        at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1508)
        at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1537)
        at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1505)
        ... 107 more
    Caused by: java.sql.SQLException: IJ031070: Transaction cannot proceed: STATUS_MARKED_ROLLBACK
        at org.jboss.jca.adapters.jdbc.WrapperDataSource.checkTransactionActive(WrapperDataSource.java:248)
        at org.jboss.jca.adapters.jdbc.WrappedConnection.checkTransactionActive(WrappedConnection.java:1933)
        at org.jboss.jca.adapters.jdbc.WrappedConnection.checkStatus(WrappedConnection.java:1948)
        at org.jboss.jca.adapters.jdbc.WrappedConnection.checkTransaction(WrappedConnection.java:1922)
        at org.jboss.jca.adapters.jdbc.WrappedConnection.prepareStatement(WrappedConnection.java:452)
        at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:146)
        at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:172)
    

    userDao.findUserByName 只需执行以下操作:

    public User findUserByName(String username) {
        return em.createNamedQuery("User.findByName", User.class)
                .setParameter("name", username)
                .getSingleResult();
    }
    

    我是否缺少一些配置?我甚至试过 @Transactional(dontRollbackOn = {NoResultException.class}) (不知道它是否对容器管理的事务有任何影响),但没有成功。

    0 回复  |  直到 8 年前