Merge branch '6.0.x'
# Conflicts: # spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java # spring-r2dbc/src/test/java/org/springframework/r2dbc/connection/R2dbcTransactionManagerUnitTests.java
This commit is contained in:
commit
3099710087
|
|
@ -1084,6 +1084,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
|||
// Let subclasses do some final clean-up if they wish...
|
||||
onClose();
|
||||
|
||||
// Reset common introspection caches to avoid class reference leaks.
|
||||
resetCommonCaches();
|
||||
|
||||
// Reset local application listeners to pre-refresh state.
|
||||
if (this.earlyApplicationListeners != null) {
|
||||
this.applicationListeners.clear();
|
||||
|
|
|
|||
|
|
@ -1326,6 +1326,9 @@ public abstract class AnnotationUtils {
|
|||
public static void clearCache() {
|
||||
AnnotationTypeMappings.clearCache();
|
||||
AnnotationsScanner.clearCache();
|
||||
AttributeMethods.cache.clear();
|
||||
RepeatableContainers.cache.clear();
|
||||
OrderUtils.orderCache.clear();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -39,9 +39,7 @@ final class AttributeMethods {
|
|||
|
||||
static final AttributeMethods NONE = new AttributeMethods(null, new Method[0]);
|
||||
|
||||
|
||||
private static final Map<Class<? extends Annotation>, AttributeMethods> cache =
|
||||
new ConcurrentReferenceHashMap<>();
|
||||
static final Map<Class<? extends Annotation>, AttributeMethods> cache = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
private static final Comparator<Method> methodComparator = (m1, m2) -> {
|
||||
if (m1 != null && m2 != null) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -41,7 +41,7 @@ public abstract class OrderUtils {
|
|||
private static final String JAVAX_PRIORITY_ANNOTATION = "jakarta.annotation.Priority";
|
||||
|
||||
/** Cache for @Order value (or NOT_ANNOTATED marker) per Class. */
|
||||
private static final Map<AnnotatedElement, Object> orderCache = new ConcurrentReferenceHashMap<>(64);
|
||||
static final Map<AnnotatedElement, Object> orderCache = new ConcurrentReferenceHashMap<>(64);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ import org.springframework.util.ObjectUtils;
|
|||
*/
|
||||
public abstract class RepeatableContainers {
|
||||
|
||||
static final Map<Class<? extends Annotation>, Object> cache = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
@Nullable
|
||||
private final RepeatableContainers parent;
|
||||
|
||||
|
|
@ -141,8 +143,6 @@ public abstract class RepeatableContainers {
|
|||
*/
|
||||
private static class StandardRepeatableContainers extends RepeatableContainers {
|
||||
|
||||
private static final Map<Class<? extends Annotation>, Object> cache = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
private static final Object NONE = new Object();
|
||||
|
||||
private static final StandardRepeatableContainers INSTANCE = new StandardRepeatableContainers();
|
||||
|
|
|
|||
|
|
@ -77,7 +77,25 @@ public abstract class LogFactory {
|
|||
*/
|
||||
@Deprecated
|
||||
public static LogFactory getFactory() {
|
||||
return new LogFactory() {};
|
||||
return new LogFactory() {
|
||||
@Override
|
||||
public Object getAttribute(String name) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String[] getAttributeNames() {
|
||||
return new String[0];
|
||||
}
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
}
|
||||
@Override
|
||||
public void setAttribute(String name, Object value) {
|
||||
}
|
||||
@Override
|
||||
public void release() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -106,29 +124,19 @@ public abstract class LogFactory {
|
|||
// Just in case some code happens to call uncommon Commons Logging methods...
|
||||
|
||||
@Deprecated
|
||||
public Object getAttribute(String name) {
|
||||
return null;
|
||||
}
|
||||
public abstract Object getAttribute(String name);
|
||||
|
||||
@Deprecated
|
||||
public String[] getAttributeNames() {
|
||||
return new String[0];
|
||||
}
|
||||
public abstract String[] getAttributeNames();
|
||||
|
||||
@Deprecated
|
||||
public void removeAttribute(String name) {
|
||||
// do nothing
|
||||
}
|
||||
public abstract void removeAttribute(String name);
|
||||
|
||||
@Deprecated
|
||||
public void setAttribute(String name, Object value) {
|
||||
// do nothing
|
||||
}
|
||||
public abstract void setAttribute(String name, Object value);
|
||||
|
||||
@Deprecated
|
||||
public void release() {
|
||||
// do nothing
|
||||
}
|
||||
public abstract void release();
|
||||
|
||||
@Deprecated
|
||||
public static void release(ClassLoader classLoader) {
|
||||
|
|
|
|||
|
|
@ -80,4 +80,8 @@ public class LogFactoryService extends LogFactory {
|
|||
return this.attributes.keySet().toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,10 +50,10 @@ import static org.mockito.Mockito.verify;
|
|||
*/
|
||||
public class JdbcTemplateQueryTests {
|
||||
|
||||
private Connection connection = mock();
|
||||
|
||||
private DataSource dataSource = mock();
|
||||
|
||||
private Connection connection = mock();
|
||||
|
||||
private Statement statement = mock();
|
||||
|
||||
private PreparedStatement preparedStatement = mock();
|
||||
|
|
|
|||
|
|
@ -75,18 +75,18 @@ import static org.mockito.Mockito.verify;
|
|||
*/
|
||||
public class JdbcTemplateTests {
|
||||
|
||||
private Connection connection = mock();
|
||||
|
||||
private DataSource dataSource = mock();
|
||||
|
||||
private Connection connection = mock();
|
||||
|
||||
private Statement statement = mock();
|
||||
|
||||
private PreparedStatement preparedStatement = mock();
|
||||
|
||||
private ResultSet resultSet = mock();
|
||||
|
||||
private CallableStatement callableStatement = mock();
|
||||
|
||||
private ResultSet resultSet = mock();
|
||||
|
||||
private JdbcTemplate template = new JdbcTemplate(this.dataSource);
|
||||
|
||||
|
||||
|
|
@ -136,9 +136,9 @@ public class JdbcTemplateTests {
|
|||
given(this.preparedStatement.executeUpdate()).willThrow(sqlException);
|
||||
|
||||
Dispatcher d = new Dispatcher(idParam, sql);
|
||||
assertThatExceptionOfType(UncategorizedSQLException.class).isThrownBy(() ->
|
||||
this.template.update(d))
|
||||
.withCause(sqlException);
|
||||
assertThatExceptionOfType(UncategorizedSQLException.class)
|
||||
.isThrownBy(() -> this.template.update(d))
|
||||
.withCause(sqlException);
|
||||
verify(this.preparedStatement).setInt(1, idParam);
|
||||
verify(this.preparedStatement).close();
|
||||
verify(this.connection, atLeastOnce()).close();
|
||||
|
|
@ -371,9 +371,9 @@ public class JdbcTemplateTests {
|
|||
given(this.statement.executeUpdate(sql)).willThrow(sqlException);
|
||||
given(this.connection.createStatement()).willReturn(this.statement);
|
||||
|
||||
assertThatExceptionOfType(DataAccessException.class).isThrownBy(() ->
|
||||
this.template.update(sql))
|
||||
.withCause(sqlException);
|
||||
assertThatExceptionOfType(DataAccessException.class)
|
||||
.isThrownBy(() -> this.template.update(sql))
|
||||
.withCause(sqlException);
|
||||
verify(this.statement).close();
|
||||
verify(this.connection, atLeastOnce()).close();
|
||||
}
|
||||
|
|
@ -700,9 +700,9 @@ public class JdbcTemplateTests {
|
|||
};
|
||||
|
||||
try {
|
||||
assertThatExceptionOfType(DataAccessException.class).isThrownBy(() ->
|
||||
this.template.batchUpdate(sql, setter))
|
||||
.withCause(sqlException);
|
||||
assertThatExceptionOfType(DataAccessException.class)
|
||||
.isThrownBy(() -> this.template.batchUpdate(sql, setter))
|
||||
.withCause(sqlException);
|
||||
}
|
||||
finally {
|
||||
verify(this.preparedStatement, times(2)).addBatch();
|
||||
|
|
@ -804,9 +804,9 @@ public class JdbcTemplateTests {
|
|||
JdbcTemplate template = new JdbcTemplate(this.dataSource, false);
|
||||
RowCountCallbackHandler rcch = new RowCountCallbackHandler();
|
||||
|
||||
assertThatExceptionOfType(CannotGetJdbcConnectionException.class).isThrownBy(() ->
|
||||
template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch))
|
||||
.withCause(sqlException);
|
||||
assertThatExceptionOfType(CannotGetJdbcConnectionException.class)
|
||||
.isThrownBy(() -> template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch))
|
||||
.withCause(sqlException);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -818,9 +818,9 @@ public class JdbcTemplateTests {
|
|||
this.template.afterPropertiesSet();
|
||||
RowCountCallbackHandler rcch = new RowCountCallbackHandler();
|
||||
|
||||
assertThatExceptionOfType(CannotGetJdbcConnectionException.class).isThrownBy(() ->
|
||||
this.template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch))
|
||||
.withCause(sqlException);
|
||||
assertThatExceptionOfType(CannotGetJdbcConnectionException.class)
|
||||
.isThrownBy(() -> this.template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch))
|
||||
.withCause(sqlException);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -858,9 +858,9 @@ public class JdbcTemplateTests {
|
|||
this.template.afterPropertiesSet();
|
||||
}
|
||||
RowCountCallbackHandler rcch = new RowCountCallbackHandler();
|
||||
assertThatExceptionOfType(CannotGetJdbcConnectionException.class).isThrownBy(() ->
|
||||
this.template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch))
|
||||
.withCause(sqlException);
|
||||
assertThatExceptionOfType(CannotGetJdbcConnectionException.class)
|
||||
.isThrownBy(() -> this.template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch))
|
||||
.withCause(sqlException);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -887,9 +887,9 @@ public class JdbcTemplateTests {
|
|||
given(this.preparedStatement.executeUpdate()).willThrow(sqlException);
|
||||
|
||||
PreparedStatementSetter pss = ps -> ps.setString(1, name);
|
||||
assertThatExceptionOfType(DataAccessException.class).isThrownBy(() ->
|
||||
new JdbcTemplate(this.dataSource).update(sql, pss))
|
||||
.withCause(sqlException);
|
||||
assertThatExceptionOfType(DataAccessException.class)
|
||||
.isThrownBy(() -> new JdbcTemplate(this.dataSource).update(sql, pss))
|
||||
.withCause(sqlException);
|
||||
verify(this.preparedStatement).setString(1, name);
|
||||
verify(this.preparedStatement).close();
|
||||
verify(this.connection, atLeastOnce()).close();
|
||||
|
|
@ -925,9 +925,9 @@ public class JdbcTemplateTests {
|
|||
t.setIgnoreWarnings(false);
|
||||
|
||||
ResultSetExtractor<Byte> extractor = rs -> rs.getByte(1);
|
||||
assertThatExceptionOfType(SQLWarningException.class).isThrownBy(() ->
|
||||
t.query(sql, extractor))
|
||||
.withCause(warnings);
|
||||
assertThatExceptionOfType(SQLWarningException.class)
|
||||
.isThrownBy(() -> t.query(sql, extractor))
|
||||
.withCause(warnings);
|
||||
verify(this.resultSet).close();
|
||||
verify(this.preparedStatement).close();
|
||||
verify(this.connection).close();
|
||||
|
|
@ -968,7 +968,7 @@ public class JdbcTemplateTests {
|
|||
this.template.query(sql, (RowCallbackHandler) rs -> {
|
||||
throw sqlException;
|
||||
}))
|
||||
.withCause(sqlException);
|
||||
.withCause(sqlException);
|
||||
verify(this.resultSet).close();
|
||||
verify(this.preparedStatement).close();
|
||||
verify(this.connection, atLeastOnce()).close();
|
||||
|
|
@ -988,7 +988,7 @@ public class JdbcTemplateTests {
|
|||
this.template.query(sql, (RowCallbackHandler) rs -> {
|
||||
throw sqlException;
|
||||
}))
|
||||
.withCause(sqlException);
|
||||
.withCause(sqlException);
|
||||
verify(this.resultSet).close();
|
||||
verify(this.preparedStatement).close();
|
||||
verify(this.connection).close();
|
||||
|
|
@ -1018,7 +1018,7 @@ public class JdbcTemplateTests {
|
|||
template.query(sql, (RowCallbackHandler) rs -> {
|
||||
throw sqlException;
|
||||
}))
|
||||
.withCause(sqlException);
|
||||
.withCause(sqlException);
|
||||
verify(this.resultSet).close();
|
||||
verify(this.preparedStatement).close();
|
||||
verify(this.connection).close();
|
||||
|
|
|
|||
|
|
@ -338,8 +338,8 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
|
|||
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;
|
||||
|
||||
if (txObject.hasSavepoint()) {
|
||||
// Just release the savepoint
|
||||
return Mono.defer(txObject::releaseSavepoint);
|
||||
// Just release the savepoint, keeping the transactional connection.
|
||||
return txObject.releaseSavepoint();
|
||||
}
|
||||
|
||||
// Remove the connection holder from the context, if exposed.
|
||||
|
|
@ -348,30 +348,25 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
|
|||
}
|
||||
|
||||
// Reset connection.
|
||||
Connection con = txObject.getConnectionHolder().getConnection();
|
||||
|
||||
Mono<Void> afterCleanup = Mono.empty();
|
||||
|
||||
Mono<Void> releaseConnectionStep = Mono.defer(() -> {
|
||||
try {
|
||||
if (txObject.isNewConnectionHolder()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Releasing R2DBC Connection [" + con + "] after transaction");
|
||||
}
|
||||
Mono<Void> releaseMono = ConnectionFactoryUtils.releaseConnection(con, obtainConnectionFactory());
|
||||
if (logger.isDebugEnabled()) {
|
||||
releaseMono = releaseMono.doOnError(
|
||||
ex -> logger.debug(String.format("Error ignored during cleanup: %s", ex)));
|
||||
}
|
||||
return releaseMono.onErrorComplete();
|
||||
try {
|
||||
if (txObject.isNewConnectionHolder()) {
|
||||
Connection con = txObject.getConnectionHolder().getConnection();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Releasing R2DBC Connection [" + con + "] after transaction");
|
||||
}
|
||||
Mono<Void> releaseMono = ConnectionFactoryUtils.releaseConnection(con, obtainConnectionFactory());
|
||||
if (logger.isDebugEnabled()) {
|
||||
releaseMono = releaseMono.doOnError(
|
||||
ex -> logger.debug(String.format("Error ignored during cleanup: %s", ex)));
|
||||
}
|
||||
return releaseMono.onErrorComplete();
|
||||
}
|
||||
finally {
|
||||
txObject.getConnectionHolder().clear();
|
||||
}
|
||||
return Mono.empty();
|
||||
});
|
||||
return afterCleanup.then(releaseConnectionStep);
|
||||
}
|
||||
finally {
|
||||
txObject.getConnectionHolder().clear();
|
||||
}
|
||||
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -517,30 +512,35 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
|
|||
}
|
||||
|
||||
public boolean hasSavepoint() {
|
||||
return this.savepointName != null;
|
||||
return (this.savepointName != null);
|
||||
}
|
||||
|
||||
public Mono<Void> createSavepoint() {
|
||||
ConnectionHolder holder = getConnectionHolder();
|
||||
this.savepointName = holder.nextSavepoint();
|
||||
return Mono.from(holder.getConnection().createSavepoint(this.savepointName));
|
||||
String currentSavepoint = holder.nextSavepoint();
|
||||
this.savepointName = currentSavepoint;
|
||||
return Mono.from(holder.getConnection().createSavepoint(currentSavepoint));
|
||||
}
|
||||
|
||||
public Mono<Void> releaseSavepoint() {
|
||||
String currentSavepointName = this.savepointName;
|
||||
String currentSavepoint = this.savepointName;
|
||||
if (currentSavepoint == null) {
|
||||
return Mono.empty();
|
||||
}
|
||||
this.savepointName = null;
|
||||
return Mono.from(getConnectionHolder().getConnection().releaseSavepoint(currentSavepointName));
|
||||
return Mono.from(getConnectionHolder().getConnection().releaseSavepoint(currentSavepoint));
|
||||
}
|
||||
|
||||
public Mono<Void> commit() {
|
||||
Connection connection = getConnectionHolder().getConnection();
|
||||
return (this.savepointName != null ? Mono.empty() : Mono.from(connection.commitTransaction()));
|
||||
return (hasSavepoint() ? Mono.empty() :
|
||||
Mono.from(getConnectionHolder().getConnection().commitTransaction()));
|
||||
}
|
||||
|
||||
public Mono<Void> rollback() {
|
||||
Connection connection = getConnectionHolder().getConnection();
|
||||
return (this.savepointName != null ?
|
||||
Mono.from(connection.rollbackTransactionToSavepoint(this.savepointName)) :
|
||||
String currentSavepoint = this.savepointName;
|
||||
return (currentSavepoint != null ?
|
||||
Mono.from(connection.rollbackTransactionToSavepoint(currentSavepoint)) :
|
||||
Mono.from(connection.rollbackTransaction()));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue