Merge branch '6.2.x'
This commit is contained in:
commit
b610711235
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -69,7 +69,13 @@ public class TaskRejectedException extends RejectedExecutionException {
|
||||||
|
|
||||||
private static String executorDescription(Executor executor) {
|
private static String executorDescription(Executor executor) {
|
||||||
if (executor instanceof ExecutorService executorService) {
|
if (executor instanceof ExecutorService executorService) {
|
||||||
return "ExecutorService in " + (executorService.isShutdown() ? "shutdown" : "active") + " state";
|
try {
|
||||||
|
return "ExecutorService in " + (executorService.isShutdown() ? "shutdown" : "active") + " state";
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
// UnsupportedOperationException/IllegalStateException from ManagedExecutorService.isShutdown()
|
||||||
|
// Falling back to toString() below.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return executor.toString();
|
return executor.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -438,7 +438,11 @@ public abstract class DataSourceUtils {
|
||||||
public static Connection getTargetConnection(Connection con) {
|
public static Connection getTargetConnection(Connection con) {
|
||||||
Connection conToUse = con;
|
Connection conToUse = con;
|
||||||
while (conToUse instanceof ConnectionProxy connectionProxy) {
|
while (conToUse instanceof ConnectionProxy connectionProxy) {
|
||||||
conToUse = connectionProxy.getTargetConnection();
|
Connection targetCon = connectionProxy.getTargetConnection();
|
||||||
|
if (targetCon == conToUse) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
conToUse = targetCon;
|
||||||
}
|
}
|
||||||
return conToUse;
|
return conToUse;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -209,13 +209,23 @@ public class TransactionAwareDataSourceProxy extends DelegatingDataSource {
|
||||||
sb.append('[').append(this.target).append(']');
|
sb.append('[').append(this.target).append(']');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sb.append(" from DataSource [").append(this.targetDataSource).append(']');
|
sb.append("from DataSource [").append(this.targetDataSource).append(']');
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
case "close" -> {
|
case "close" -> {
|
||||||
// Handle close method: only close if not within a transaction.
|
// Handle close method: only close if not within a transaction.
|
||||||
DataSourceUtils.doReleaseConnection(this.target, this.targetDataSource);
|
if (this.target != null) {
|
||||||
|
ConnectionHolder conHolder = (ConnectionHolder)
|
||||||
|
TransactionSynchronizationManager.getResource(this.targetDataSource);
|
||||||
|
if (conHolder != null && conHolder.hasConnection() && conHolder.getConnection() == this.target) {
|
||||||
|
// It's the transactional Connection: Don't close it.
|
||||||
|
conHolder.released();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DataSourceUtils.doCloseConnection(this.target, this.targetDataSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.closed = true;
|
this.closed = true;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -72,7 +72,7 @@ public class DataSourceTransactionManagerTests {
|
||||||
|
|
||||||
protected DataSource ds = mock();
|
protected DataSource ds = mock();
|
||||||
|
|
||||||
protected Connection con = mock();
|
protected ConnectionProxy con = mock();
|
||||||
|
|
||||||
protected DataSourceTransactionManager tm;
|
protected DataSourceTransactionManager tm;
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@ public class DataSourceTransactionManagerTests {
|
||||||
void setup() throws Exception {
|
void setup() throws Exception {
|
||||||
tm = createTransactionManager(ds);
|
tm = createTransactionManager(ds);
|
||||||
given(ds.getConnection()).willReturn(con);
|
given(ds.getConnection()).willReturn(con);
|
||||||
|
given(con.getTargetConnection()).willThrow(new UnsupportedOperationException());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DataSourceTransactionManager createTransactionManager(DataSource ds) {
|
protected DataSourceTransactionManager createTransactionManager(DataSource ds) {
|
||||||
|
@ -1073,9 +1074,9 @@ public class DataSourceTransactionManagerTests {
|
||||||
Connection tCon = dsProxy.getConnection();
|
Connection tCon = dsProxy.getConnection();
|
||||||
tCon.getWarnings();
|
tCon.getWarnings();
|
||||||
tCon.clearWarnings();
|
tCon.clearWarnings();
|
||||||
assertThat(((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()).isEqualTo(con);
|
assertThat(((ConnectionProxy) tCon).getTargetConnection()).isEqualTo(con);
|
||||||
// should be ignored
|
// should be ignored
|
||||||
dsProxy.getConnection().close();
|
tCon.close();
|
||||||
}
|
}
|
||||||
catch (SQLException ex) {
|
catch (SQLException ex) {
|
||||||
throw new UncategorizedSQLException("", "", ex);
|
throw new UncategorizedSQLException("", "", ex);
|
||||||
|
@ -1109,9 +1110,9 @@ public class DataSourceTransactionManagerTests {
|
||||||
Connection tCon = dsProxy.getConnection();
|
Connection tCon = dsProxy.getConnection();
|
||||||
assertThatExceptionOfType(SQLException.class).isThrownBy(tCon::getWarnings);
|
assertThatExceptionOfType(SQLException.class).isThrownBy(tCon::getWarnings);
|
||||||
tCon.clearWarnings();
|
tCon.clearWarnings();
|
||||||
assertThat(((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()).isEqualTo(con);
|
assertThat(((ConnectionProxy) tCon).getTargetConnection()).isEqualTo(con);
|
||||||
// should be ignored
|
// should be ignored
|
||||||
dsProxy.getConnection().close();
|
tCon.close();
|
||||||
}
|
}
|
||||||
catch (SQLException ex) {
|
catch (SQLException ex) {
|
||||||
throw new UncategorizedSQLException("", "", ex);
|
throw new UncategorizedSQLException("", "", ex);
|
||||||
|
@ -1127,6 +1128,42 @@ public class DataSourceTransactionManagerTests {
|
||||||
verify(con).close();
|
verify(con).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testTransactionAwareDataSourceProxyWithEarlyConnection() throws Exception {
|
||||||
|
given(ds.getConnection()).willReturn(mock(Connection.class), con);
|
||||||
|
given(con.getAutoCommit()).willReturn(true);
|
||||||
|
given(con.getWarnings()).willThrow(new SQLException());
|
||||||
|
|
||||||
|
TransactionAwareDataSourceProxy dsProxy = new TransactionAwareDataSourceProxy(ds);
|
||||||
|
dsProxy.setLazyTransactionalConnections(false);
|
||||||
|
Connection tCon = dsProxy.getConnection();
|
||||||
|
|
||||||
|
TransactionTemplate tt = new TransactionTemplate(tm);
|
||||||
|
assertThat(TransactionSynchronizationManager.hasResource(ds)).isFalse();
|
||||||
|
tt.execute(new TransactionCallbackWithoutResult() {
|
||||||
|
@Override
|
||||||
|
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
|
// something transactional
|
||||||
|
assertThat(DataSourceUtils.getConnection(ds)).isEqualTo(con);
|
||||||
|
try {
|
||||||
|
// should close the early Connection obtained before the transaction
|
||||||
|
tCon.close();
|
||||||
|
}
|
||||||
|
catch (SQLException ex) {
|
||||||
|
throw new UncategorizedSQLException("", "", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThat(TransactionSynchronizationManager.hasResource(ds)).isFalse();
|
||||||
|
|
||||||
|
InOrder ordered = inOrder(con);
|
||||||
|
ordered.verify(con).setAutoCommit(false);
|
||||||
|
ordered.verify(con).commit();
|
||||||
|
ordered.verify(con).setAutoCommit(true);
|
||||||
|
verify(con).close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testTransactionAwareDataSourceProxyWithSuspension() throws Exception {
|
void testTransactionAwareDataSourceProxyWithSuspension() throws Exception {
|
||||||
given(con.getAutoCommit()).willReturn(true);
|
given(con.getAutoCommit()).willReturn(true);
|
||||||
|
|
Loading…
Reference in New Issue