В настоящее время мы используем HikariCP для управления нашим пулом соединений.
Учитывая приведенный ниже фрагмент кода, мы сталкиваемся со следующей проблемой:
try{
txn.begin();
entityManager.persist(someEntity);
txn.commit();// Line 1
} catch(Throwable tx ){
if(txn.isActive()){
txn.rollback(); //Line 2
}
}
EntityManager пытается выполнить коммит длячто ему нужно соединение с HikariCP.Hikari истекает, и, поскольку мы не получили никакого соединения с базой данных, это приводит к исключению.Теперь при попытке отката транзакции последовательность отката пытается снова установить соединение -
- Если соединение не найдено, оно снова не удается,
- Если соединение найдено изБассейн, он используется.По умолчанию соединение находится в режиме autocommit = true, поэтому откат не выполняется, и пул помечает соединение как разорванное, поскольку ожидаемое состояние соединения при откате - autocommit = 0.
Этостранно, потому что можно предположить, что откат должен происходить на том же соединении, что и при попытке фиксации;если соединение не найдено, откат не должен предприниматься.однако это не то, что происходит.Это приводит к тому, что исправные соединения помечаются как разорванные, и этот цикл повторяется в большинстве 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 Connector: 8.0.11 Eclipselink: 2.5.2 / 2.7 оба пробовали.Двигатель: Innodb.
Редактировать: трассировка стека добавлена по запросу:
08 мая 2018 г. 13: 18: 39,468 - [Thread-159847] - [1161705814: 77] - ПРЕДУПРЕЖДЕНИЕ - Исключение ProxyConnection.checkException (156) - HikariPool-1 - Соединение com.mysql.jdbc.JDBC4Connection@47f8b848 помечено как разорванное из-за SQLSTATE (08003), ErrorCode (0) com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: не удается вызвать откат, когда autocommit = true на солнце.reflect.(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:z3xer.h).pool.ProxyConnection.rollback (ProxyConnection.java:361) на com.zaxxer.hikari.pool.HikariProxyConnection.rollback (HikariProxyConnection.java) на org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicRollback00jj) в org.eclipse.persistence.internal.databaseaccess.DatasourceAccessor.rollbackTransaction (DatasourceAccessor.java:688) в org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.rollbackTransaction (DatabaseAccessor.java:1691) в org.ecl.internal.sessions.AbstractSession.basicRollbackTransaction (AbstractSession.java:779) в org.eclipse.persistence.sessions.server.ClientSession.basicRollbackTransaction (ClientSession.java:196) в org.eclipse.persistence.internal.sessions.backTactionaction (AbstractSession.java:3795) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.rollbackTransaction (UnitOfWorkImpl.java:4670)в org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.rollbackTransaction (RepeatableWriteUnitOfWork.java:529) в org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.rollbackatjWW.ReU.sessions.UnitOfWorkImpl.commitToDatabase (UnitOfWorkImpl.java:1480) при org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet (UnitOfWorkImpl.java:1531) в org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork (RepeatableWriteUnitOfWork0com.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)