由于没有连接而提交失败时的回滚行为

时间:2018-05-15 19:05:31

标签: java jdbc eclipselink rollback hikaricp

目前,我们正在使用HikariCP来管理我们的连接池。

鉴于下面提到的代码段,我们面临以下问题:

try{
    txn.begin(); 
    entityManager.persist(someEntity);
    txn.commit();// Line 1
} catch(Throwable tx ){
   if(txn.isActive()){
    txn.rollback(); //Line 2
   }
}

EntityManager尝试提交,因为它需要来自HikariCP的连接。 Hikari超时,因为我们没有得到任何数据库连接,这导致异常。现在,当尝试回滚事务时,回滚序列会尝试再次建立连接 -

  1. 如果未找到连接,则会再次失败,
  2. 如果从池中找到连接,则使用它。默认情况下,连接处于autocommit = true模式,因此回滚失败,并且Pool将连接标记为已损坏,因为回滚时预期的连接状态为autocommit = 0.
  3. 这很奇怪,因为人们会认为回滚应该在尝试提交的同一连接上发生;如果未找到连接,则不应尝试回滚。然而,这不是正在发生的事情。这会导致健康的连接被标记为已损坏,并且只要池上有压力,此循环就会在大多数API中重复。

    我们正在使用EclipseLink版本2.5.2,但即使在最新版本中也存在此问题。我可以将它追溯到DatasourceAccessor.java中的回滚序列的这一部分:

     public synchronized void incrementCallCount(AbstractSession session) {
        this.callCount++;
    
        if (this.callCount == 1) {
            // If the login is null, then this accessor has never been connected.
            if (this.login == null) {
                throw DatabaseException.databaseAccessorNotConnected();
            }
    
            // If the connection is no longer connected, it may have timed out.
            if (this.datasourceConnection != null) {
                if (shouldCheckConnection && !isConnected()) {
                    if (this.isInTransaction) {
                        throw DatabaseException.databaseAccessorNotConnected();
                    } else {
                        reconnect(session);
                    }
                }
            } else {
                // If ExternalConnectionPooling is used, the connection can be re-established.
                if (this.usesExternalConnectionPooling) {
                    reconnect(session); //Why reconnect?
                    session.postAcquireConnection(this);
                    currentSession = session;
                } else {
                    throw DatabaseException.databaseAccessorNotConnected();
                }
            }
        }
    }
    

    恕我直言,在进行回滚时,不应获取新连接。这没有道理。我错过了什么吗?

    Java:1.8.0_91 Hikari:3.0.1 MySQL连接器:8.0.11 Eclipselink:2.5.2 / 2.7都尝试过。 发动机:Innodb。

    编辑:按要求添加Stacktrace:

    2018年5月8日13:18:39,468 - [Thread-159847] - [1161705814:77] - WARN - ProxyConnection.checkException(156) - HikariPool-1 - 连接com.mysql.jdbc.JDBC4Connection@47f8b848标记为 由于SQLSTATE(08003)而被破坏,ErrorCode(0) com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException:当autocommit = true时无法调用回滚         at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)         at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)         at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)         at java.lang.reflect.Constructor.newInstance(Constructor.java:423)         在com.mysql.jdbc.Util.handleNewInstance(Util.java:408)         在com.mysql.jdbc.Util.getInstance(Util.java:383)         在com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1023)         在com.mysql.jdbc.SQLError.createSQLException(SQLError.java:997)         在com.mysql.jdbc.SQLError.createSQLException(SQLError.java:983)         在com.mysql.jdbc.SQLError.createSQLException(SQLError.java:928)         在com.mysql.jdbc.ConnectionImpl.rollback(ConnectionImpl.java:5078)         在com.zaxxer.hikari.pool.ProxyConnection.rollback(ProxyConnection.java:361)         在com.zaxxer.hikari.pool.HikariProxyConnection.rollback(HikariProxyConnection.java)         at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicRollbackTransaction(DatabaseAccessor.java:1700)         at org.eclipse.persistence.internal.databaseaccess.DatasourceAccessor.rollbackTransaction(DatasourceAccessor.java:688)         在org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.rollbackTransaction(DatabaseAccessor.java:1691)         at org.eclipse.persistence.internal.sessions.AbstractSession.basicRollbackTransaction(AbstractSession.java:779)         在org.eclipse.persistence.sessions.server.ClientSession.basicRollbackTransaction(ClientSession.java:196)         at org.eclipse.persistence.internal.sessions.AbstractSession.rollbackTransaction(AbstractSession.java:3795)         at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.rollbackTransaction(UnitOfWorkImpl.java:4670)         at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.rollbackTransaction(RepeatableWriteUnitOfWork.java:529)         at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.rollbackTransaction(RepeatableWriteUnitOfWork.java:545)         at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1480)         at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1531)         at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:277)         at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1169)         at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:132)         在com.paytm.wallet.dao.domain.UserBeneficiaryManager.updateBenefeciaryDetails(UserBeneficiaryManager.java:81)         在com.paytm.wallet.web.wrapper.business.impl.UserBeneficiaryHelper.addBeneficary(UserBeneficiaryHelper.java:247)         在com.paytm.wallet.web.concurrent.AddBeneficiaryThread.run(AddBeneficiaryThread.java:36)         在java.lang.Thread.run(Thread.java:745)

0 个答案:

没有答案