diff --git a/spring-core/src/main/java/org/springframework/aot/AotDetector.java b/spring-core/src/main/java/org/springframework/aot/AotDetector.java index a3c1740733..4ecac5d35b 100644 --- a/spring-core/src/main/java/org/springframework/aot/AotDetector.java +++ b/spring-core/src/main/java/org/springframework/aot/AotDetector.java @@ -39,7 +39,8 @@ public abstract class AotDetector { */ public static final String AOT_ENABLED = "spring.aot.enabled"; - private static final boolean inNativeImage = NativeDetector.inNativeImage(Context.RUNTIME, Context.BUILD_TIME); + private static final boolean inNativeImage = NativeDetector.inNativeImage(Context.RUN, Context.BUILD); + /** * Determine whether AOT optimizations must be considered at runtime. This diff --git a/spring-core/src/main/java/org/springframework/core/NativeDetector.java b/spring-core/src/main/java/org/springframework/core/NativeDetector.java index a588864234..46d72b7bdd 100644 --- a/spring-core/src/main/java/org/springframework/core/NativeDetector.java +++ b/spring-core/src/main/java/org/springframework/core/NativeDetector.java @@ -32,6 +32,7 @@ public abstract class NativeDetector { private static final boolean inNativeImage = (imageCode != null); + /** * Returns {@code true} if running in a native image context (for example * {@code buildtime}, {@code runtime}, or {@code agent}) expressed by setting the @@ -55,10 +56,10 @@ public abstract class NativeDetector { return false; } + /** * Native image context as defined in GraalVM's * ImageInfo. - * * @since 6.0.10 */ public enum Context { @@ -66,12 +67,12 @@ public abstract class NativeDetector { /** * The code is executing in the context of image building. */ - BUILD_TIME("buildtime"), + BUILD("buildtime"), /** * The code is executing at image runtime. */ - RUNTIME("runtime"); + RUN("runtime"); private final String key; @@ -83,7 +84,6 @@ public abstract class NativeDetector { public String toString() { return this.key; } - } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceTransactionManager.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceTransactionManager.java index 5091abead3..2965ebff03 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceTransactionManager.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceTransactionManager.java @@ -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. @@ -35,49 +35,52 @@ import org.springframework.transaction.support.TransactionSynchronizationUtils; import org.springframework.util.Assert; /** - * {@link org.springframework.transaction.PlatformTransactionManager} - * implementation for a single JDBC {@link javax.sql.DataSource}. This class is - * capable of working in any environment with any JDBC driver, as long as the setup - * uses a {@code javax.sql.DataSource} as its {@code Connection} factory mechanism. - * Binds a JDBC Connection from the specified DataSource to the current thread, - * potentially allowing for one thread-bound Connection per DataSource. + * {@link org.springframework.transaction.PlatformTransactionManager} implementation + * for a single JDBC {@link javax.sql.DataSource}. This class is capable of working + * in any environment with any JDBC driver, as long as the setup uses a + * {@code javax.sql.DataSource} as its {@code Connection} factory mechanism. + * Binds a JDBC {@code Connection} from the specified {@code DataSource} to the + * current thread, potentially allowing for one thread-bound {@code Connection} + * per {@code DataSource}. * - *
Note: The DataSource that this transaction manager operates on needs - * to return independent Connections. The Connections may come from a pool - * (the typical case), but the DataSource must not return thread-scoped / - * request-scoped Connections or the like. This transaction manager will - * associate Connections with thread-bound transactions itself, according - * to the specified propagation behavior. It assumes that a separate, - * independent Connection can be obtained even during an ongoing transaction. + *
Note: The {@code DataSource} that this transaction manager operates on + * needs to return independent {@code Connection}s. The {@code Connection}s + * typically come from a connection pool but the {@code DataSource} must not return + * specifically scoped or constrained {@code Connection}s. This transaction manager + * will associate {@code Connection}s with thread-bound transactions, according + * to the specified propagation behavior. It assumes that a separate, independent + * {@code Connection} can be obtained even during an ongoing transaction. * - *
Application code is required to retrieve the JDBC Connection via + *
Application code is required to retrieve the JDBC {@code Connection} via * {@link DataSourceUtils#getConnection(DataSource)} instead of a standard - * Jakarta EE-style {@link DataSource#getConnection()} call. Spring classes such as + * EE-style {@link DataSource#getConnection()} call. Spring classes such as * {@link org.springframework.jdbc.core.JdbcTemplate} use this strategy implicitly. * If not used in combination with this transaction manager, the * {@link DataSourceUtils} lookup strategy behaves exactly like the native - * DataSource lookup; it can thus be used in a portable fashion. + * {@code DataSource} lookup; it can thus be used in a portable fashion. * *
Alternatively, you can allow application code to work with the standard - * Jakarta EE-style lookup pattern {@link DataSource#getConnection()}, for example for - * legacy code that is not aware of Spring at all. In that case, define a - * {@link TransactionAwareDataSourceProxy} for your target DataSource, and pass - * that proxy DataSource to your DAOs, which will automatically participate in - * Spring-managed transactions when accessing it. + * EE-style lookup pattern {@link DataSource#getConnection()}, for example + * for legacy code that is not aware of Spring at all. In that case, define a + * {@link TransactionAwareDataSourceProxy} for your target {@code DataSource}, + * and pass that proxy {@code DataSource} to your DAOs which will automatically + * participate in Spring-managed transactions when accessing it. * *
Supports custom isolation levels, and timeouts which get applied as * appropriate JDBC statement timeouts. To support the latter, application code * must either use {@link org.springframework.jdbc.core.JdbcTemplate}, call - * {@link DataSourceUtils#applyTransactionTimeout} for each created JDBC Statement, - * or go through a {@link TransactionAwareDataSourceProxy} which will create - * timeout-aware JDBC Connections and Statements automatically. + * {@link DataSourceUtils#applyTransactionTimeout} for each created JDBC + * {@code Statement}, or go through a {@link TransactionAwareDataSourceProxy} + * which will create timeout-aware JDBC {@code Connection}s and {@code Statement}s + * automatically. * *
Consider defining a {@link LazyConnectionDataSourceProxy} for your target - * DataSource, pointing both this transaction manager and your DAOs to it. + * {@code DataSource}, pointing both this transaction manager and your DAOs to it. * This will lead to optimized handling of "empty" transactions, i.e. of transactions - * without any JDBC statements executed. A LazyConnectionDataSourceProxy will not fetch - * an actual JDBC Connection from the target DataSource until a Statement gets executed, - * lazily applying the specified transaction settings to the target Connection. + * without any JDBC statements executed. A {@code LazyConnectionDataSourceProxy} will + * not fetch an actual JDBC {@code Connection} from the target {@code DataSource} + * until a {@code Statement} gets executed, lazily applying the specified transaction + * settings to the target {@code Connection}. * *
This transaction manager supports nested transactions via the JDBC 3.0 * {@link java.sql.Savepoint} mechanism. The @@ -88,9 +91,9 @@ import org.springframework.util.Assert; *
This transaction manager can be used as a replacement for the * {@link org.springframework.transaction.jta.JtaTransactionManager} in the single * resource case, as it does not require a container that supports JTA, typically - * in combination with a locally defined JDBC DataSource (e.g. an Apache Commons - * DBCP connection pool). Switching between this local strategy and a JTA - * environment is just a matter of configuration! + * in combination with a locally defined JDBC {@code DataSource} (e.g. a Hikari + * connection pool). Switching between this local strategy and a JTA environment + * is just a matter of configuration! * *
As of 4.3.4, this transaction manager triggers flush callbacks on registered * transaction synchronizations (if synchronization is generally active), assuming @@ -112,6 +115,7 @@ import org.springframework.util.Assert; * @see TransactionAwareDataSourceProxy * @see LazyConnectionDataSourceProxy * @see org.springframework.jdbc.core.JdbcTemplate + * @see org.springframework.jdbc.support.JdbcTransactionManager */ @SuppressWarnings("serial") public class DataSourceTransactionManager extends AbstractPlatformTransactionManager @@ -124,8 +128,8 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan /** - * Create a new DataSourceTransactionManager instance. - * A DataSource has to be set to be able to use it. + * Create a new {@code DataSourceTransactionManager} instance. + * A {@code DataSource} has to be set to be able to use it. * @see #setDataSource */ public DataSourceTransactionManager() { @@ -133,7 +137,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan } /** - * Create a new DataSourceTransactionManager instance. + * Create a new {@code DataSourceTransactionManager} instance. * @param dataSource the JDBC DataSource to manage transactions for */ public DataSourceTransactionManager(DataSource dataSource) { @@ -144,22 +148,22 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan /** - * Set the JDBC DataSource that this instance should manage transactions for. - *
This will typically be a locally defined DataSource, for example an - * Apache Commons DBCP connection pool. Alternatively, you can also drive - * transactions for a non-XA J2EE DataSource fetched from JNDI. For an XA - * DataSource, use JtaTransactionManager. - *
The DataSource specified here should be the target DataSource to manage - * transactions for, not a TransactionAwareDataSourceProxy. Only data access - * code may work with TransactionAwareDataSourceProxy, while the transaction - * manager needs to work on the underlying target DataSource. If there's - * nevertheless a TransactionAwareDataSourceProxy passed in, it will be - * unwrapped to extract its target DataSource. - *
The DataSource passed in here needs to return independent Connections. - * The Connections may come from a pool (the typical case), but the DataSource - * must not return thread-scoped / request-scoped Connections or the like. - * @see TransactionAwareDataSourceProxy - * @see org.springframework.transaction.jta.JtaTransactionManager + * Set the JDBC {@code DataSource} that this instance should manage transactions for. + *
This will typically be a locally defined {@code DataSource}, for example a + * Hikari connection pool. Alternatively, you can also manage transactions for a + * non-XA {@code DataSource} fetched from JNDI. For an XA {@code DataSource}, + * use {@link org.springframework.transaction.jta.JtaTransactionManager} instead. + *
The {@code DataSource} specified here should be the target {@code DataSource} + * to manage transactions for, not a {@link TransactionAwareDataSourceProxy}. + * Only data access code may work with {@code TransactionAwareDataSourceProxy} while + * the transaction manager needs to work on the underlying target {@code DataSource}. + * If there is nevertheless a {@code TransactionAwareDataSourceProxy} passed in, + * it will be unwrapped to extract its target {@code DataSource}. + *
The {@code DataSource} passed in here needs to return independent + * {@code Connection}s. The {@code Connection}s typically come from a + * connection pool but the {@code DataSource} must not return specifically + * scoped or constrained {@code Connection}s, just possibly lazily fetched. + * @see LazyConnectionDataSourceProxy */ public void setDataSource(@Nullable DataSource dataSource) { if (dataSource instanceof TransactionAwareDataSourceProxy tadsp) { @@ -174,7 +178,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan } /** - * Return the JDBC DataSource that this instance manages transactions for. + * Return the JDBC {@code DataSource} that this instance manages transactions for. */ @Nullable public DataSource getDataSource() { @@ -182,7 +186,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan } /** - * Obtain the DataSource for actual use. + * Obtain the {@code DataSource} for actual use. * @return the DataSource (never {@code null}) * @throws IllegalStateException in case of no DataSource set * @since 5.0 diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java index f730ea1432..2787b30d90 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java @@ -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. @@ -33,9 +33,9 @@ import org.springframework.transaction.support.TransactionSynchronizationManager import org.springframework.util.Assert; /** - * Helper class that provides static methods for obtaining JDBC Connections from - * a {@link javax.sql.DataSource}. Includes special support for Spring-managed - * transactional Connections, e.g. managed by {@link DataSourceTransactionManager} + * Helper class that provides static methods for obtaining JDBC {@code Connection}s + * from a {@link javax.sql.DataSource}. Includes special support for Spring-managed + * transactional {@code Connection}s, e.g. managed by {@link DataSourceTransactionManager} * or {@link org.springframework.transaction.jta.JtaTransactionManager}. * *
Used internally by Spring's {@link org.springframework.jdbc.core.JdbcTemplate}, @@ -46,7 +46,8 @@ import org.springframework.util.Assert; * @author Juergen Hoeller * @see #getConnection * @see #releaseConnection - * @see DataSourceTransactionManager + * @see org.springframework.jdbc.core.JdbcTemplate + * @see org.springframework.jdbc.support.JdbcTransactionManager * @see org.springframework.transaction.jta.JtaTransactionManager * @see org.springframework.transaction.support.TransactionSynchronizationManager */ @@ -310,8 +311,7 @@ public abstract class DataSourceUtils { } /** - * Apply the current transaction timeout, if any, - * to the given JDBC Statement object. + * Apply the current transaction timeout, if any, to the given JDBC Statement object. * @param stmt the JDBC Statement object * @param dataSource the DataSource that the Connection was obtained from * @throws SQLException if thrown by JDBC methods diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java b/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java index 254e9f1e24..07ee18b10b 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java @@ -105,7 +105,7 @@ import org.springframework.util.Assert; * @see DataSourceUtils#getConnection * @see DataSourceUtils#releaseConnection * @see org.springframework.jdbc.core.JdbcTemplate - * @see org.springframework.jdbc.datasource.DataSourceTransactionManager + * @see org.springframework.jdbc.support.JdbcTransactionManager * @see org.springframework.transaction.jta.JtaTransactionManager */ @SuppressWarnings("serial") diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java b/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java index baa0aff8c0..a82cb0722f 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java @@ -110,7 +110,7 @@ import org.springframework.util.CollectionUtils; * @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection * @see org.springframework.jdbc.core.JdbcTemplate - * @see org.springframework.jdbc.datasource.DataSourceTransactionManager + * @see org.springframework.jdbc.support.JdbcTransactionManager * @see org.springframework.transaction.jta.JtaTransactionManager */ @SuppressWarnings("serial") diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionHolder.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionHolder.java index 5ad913d0b8..dd1b9c36c7 100644 --- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionHolder.java +++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/ConnectionHolder.java @@ -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,11 +41,20 @@ import org.springframework.util.Assert; */ public class ConnectionHolder extends ResourceHolderSupport { + /** + * Prefix for savepoint names. + * @since 6.0.10 + */ + static final String SAVEPOINT_NAME_PREFIX = "SAVEPOINT_"; + + @Nullable private Connection currentConnection; private boolean transactionActive; + private int savepointCounter = 0; + /** * Create a new ConnectionHolder for the given R2DBC {@link Connection}, @@ -112,6 +121,17 @@ public class ConnectionHolder extends ResourceHolderSupport { return this.currentConnection; } + /** + * Create a new savepoint for the current {@link Connection}, + * using generated savepoint names that are unique for the Connection. + * @return the name of the new savepoint + * @since 6.0.10 + */ + String nextSavepoint() { + this.savepointCounter++; + return SAVEPOINT_NAME_PREFIX + this.savepointCounter; + } + /** * Releases the current {@link Connection}. */ diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java index 1143aa1a7f..9fe2e1140e 100644 --- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java +++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/connection/R2dbcTransactionManager.java @@ -24,7 +24,6 @@ import io.r2dbc.spi.IsolationLevel; import io.r2dbc.spi.Option; import io.r2dbc.spi.R2dbcException; import io.r2dbc.spi.Result; -import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import org.springframework.beans.factory.InitializingBean; @@ -38,46 +37,42 @@ import org.springframework.transaction.reactive.TransactionSynchronizationManage import org.springframework.util.Assert; /** - * {@link org.springframework.transaction.ReactiveTransactionManager} - * implementation for a single R2DBC {@link ConnectionFactory}. This class is - * capable of working in any environment with any R2DBC driver, as long as the - * setup uses a {@code ConnectionFactory} as its {@link Connection} factory - * mechanism. Binds a R2DBC {@code Connection} from the specified - * {@code ConnectionFactory} to the current subscriber context, potentially - * allowing for one context-bound {@code Connection} per {@code ConnectionFactory}. + * {@link org.springframework.transaction.ReactiveTransactionManager} implementation + * for a single R2DBC {@link ConnectionFactory}. This class is capable of working + * in any environment with any R2DBC driver, as long as the setup uses a + * {@code ConnectionFactory} as its {@link Connection} factory mechanism. + * Binds a R2DBC {@code Connection} from the specified {@code ConnectionFactory} + * to the current subscriber context, potentially allowing for one context-bound + * {@code Connection} per {@code ConnectionFactory}. * - *
Note: The {@code ConnectionFactory} that this transaction manager - * operates on needs to return independent {@code Connection}s. - * The {@code Connection}s may come from a pool (the typical case), but the - * {@code ConnectionFactory} must not return scoped {@code Connection}s - * or the like. This transaction manager will associate {@code Connection} - * with context-bound transactions itself, according to the specified propagation - * behavior. It assumes that a separate, independent {@code Connection} can - * be obtained even during an ongoing transaction. + *
Note: The {@code ConnectionFactory} that this transaction manager operates + * on needs to return independent {@code Connection}s. The {@code Connection}s + * typically come from a connection pool but the {@code ConnectionFactory} must not + * return specifically scoped or constrained {@code Connection}s. This transaction + * manager will associate {@code Connection} with context-bound transactions, + * according to the specified propagation behavior. It assumes that a separate, + * independent {@code Connection} can be obtained even during an ongoing transaction. * *
Application code is required to retrieve the R2DBC Connection via * {@link ConnectionFactoryUtils#getConnection(ConnectionFactory)} * instead of a standard R2DBC-style {@link ConnectionFactory#create()} call. * Spring classes such as {@code DatabaseClient} use this strategy implicitly. * If not used in combination with this transaction manager, the - * {@link ConnectionFactoryUtils} lookup strategy behaves exactly like the - * native {@code ConnectionFactory} lookup; it can thus be used in a portable fashion. + * {@link ConnectionFactoryUtils} lookup strategy behaves exactly like the native + * {@code ConnectionFactory} lookup; it can thus be used in a portable fashion. * - *
Alternatively, you can allow application code to work with the standard - * R2DBC lookup pattern {@link ConnectionFactory#create()}, for example for code - * that is not aware of Spring at all. In that case, define a - * {@link TransactionAwareConnectionFactoryProxy} for your target {@code ConnectionFactory}, - * and pass that proxy {@code ConnectionFactory} to your DAOs, which will automatically - * participate in Spring-managed transactions when accessing it. + *
Alternatively, you can allow application code to work with the lookup pattern + * {@link ConnectionFactory#create()}, for example for code not aware of Spring. + * In that case, define a {@link TransactionAwareConnectionFactoryProxy} for your + * target {@code ConnectionFactory}, and pass that proxy {@code ConnectionFactory} + * to your DAOs which will automatically participate in Spring-managed transactions + * when accessing it. * - *
This transaction manager triggers flush callbacks on registered transaction - * synchronizations (if synchronization is generally active), assuming resources - * operating on the underlying R2DBC {@code Connection}. - * - *
Spring's {@code TransactionDefinition} attributes are carried forward to R2DBC drivers - * using extensible R2DBC {@link io.r2dbc.spi.TransactionDefinition}. Subclasses may - * override {@link #createTransactionDefinition(TransactionDefinition)} to customize - * transaction definitions for vendor-specific attributes. + *
Spring's {@code TransactionDefinition} attributes are carried forward to + * R2DBC drivers using extensible R2DBC {@link io.r2dbc.spi.TransactionDefinition}. + * Subclasses may override {@link #createTransactionDefinition(TransactionDefinition)} + * to customize transaction definitions for vendor-specific attributes. As of 6.0.10, + * this transaction manager supports nested transactions via R2DBC savepoints as well. * * @author Mark Paluch * @author Juergen Hoeller @@ -97,7 +92,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager /** * Create a new {@code R2dbcTransactionManager} instance. - * A ConnectionFactory has to be set to be able to use it. + * A {@code ConnectionFactory} has to be set to be able to use it. * @see #setConnectionFactory */ public R2dbcTransactionManager() {} @@ -114,12 +109,13 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager /** - * Set the R2DBC {@link ConnectionFactory} that this instance should manage transactions for. - *
This will typically be a locally defined {@code ConnectionFactory}, for example a connection pool. - *
The {@code ConnectionFactory} passed in here needs to return independent {@link Connection}s. - * The {@code Connection}s may come from a pool (the typical case), but the {@code ConnectionFactory} - * must not return scoped {@code Connection}s or the like. - * @see TransactionAwareConnectionFactoryProxy + * Set the R2DBC {@link ConnectionFactory} that this instance should manage transactions + * for. This will typically be a locally defined {@code ConnectionFactory}, for example + * an R2DBC connection pool. + *
The {@code ConnectionFactory} passed in here needs to return independent
+ * {@link Connection}s. The {@code Connection}s typically come from a connection
+ * pool but the {@code ConnectionFactory} must not return specifically scoped or
+ * constrained {@code Connection}s.
*/
public void setConnectionFactory(@Nullable ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
@@ -183,8 +179,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
@Override
protected boolean isExistingTransaction(Object transaction) {
- ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;
- return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
+ return ((ConnectionFactoryTransactionObject) transaction).isTransactionActive();
}
@Override
@@ -193,6 +188,11 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) transaction;
+ if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED &&
+ txObject.isTransactionActive()) {
+ return txObject.createSavepoint();
+ }
+
return Mono.defer(() -> {
Mono