1
1
/*
2
- * Copyright 2002-2021 the original author or authors.
2
+ * Copyright 2002-2022 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
47
47
* <p><b>Note: The {@code ConnectionFactory} that this transaction manager
48
48
* operates on needs to return independent {@code Connection}s.</b>
49
49
* The {@code Connection}s may come from a pool (the typical case), but the
50
- * {@code ConnectionFactory} must not return scoped scoped {@code Connection}s
50
+ * {@code ConnectionFactory} must not return scoped {@code Connection}s
51
51
* or the like. This transaction manager will associate {@code Connection}
52
52
* with context-bound transactions itself, according to the specified propagation
53
53
* behavior. It assumes that a separate, independent {@code Connection} can
@@ -142,8 +142,8 @@ protected ConnectionFactory obtainConnectionFactory() {
142
142
* transactional connection: "SET TRANSACTION READ ONLY" as understood by Oracle,
143
143
* MySQL and Postgres.
144
144
* <p>The exact treatment, including any SQL statement executed on the connection,
145
- * can be customized through through {@link #prepareTransactionalConnection}.
146
- * @see #prepareTransactionalConnection
145
+ * can be customized through {@link #prepareTransactionalConnection(Connection, TransactionDefinition) }.
146
+ * @see #prepareTransactionalConnection(Connection, TransactionDefinition)
147
147
*/
148
148
public void setEnforceReadOnly (boolean enforceReadOnly ) {
149
149
this .enforceReadOnly = enforceReadOnly ;
@@ -179,6 +179,7 @@ protected boolean isExistingTransaction(Object transaction) {
179
179
return (txObject .hasConnectionHolder () && txObject .getConnectionHolder ().isTransactionActive ());
180
180
}
181
181
182
+ @ SuppressWarnings ("deprecation" )
182
183
@ Override
183
184
protected Mono <Void > doBegin (TransactionSynchronizationManager synchronizationManager , Object transaction ,
184
185
TransactionDefinition definition ) throws TransactionException {
@@ -202,27 +203,27 @@ protected Mono<Void> doBegin(TransactionSynchronizationManager synchronizationMa
202
203
connectionMono = Mono .just (txObject .getConnectionHolder ().getConnection ());
203
204
}
204
205
205
- return connectionMono .flatMap (con -> {
206
- return prepareTransactionalConnection ( con , definition , transaction ) .then (Mono .from (con .beginTransaction ()))
207
- . doOnSuccess ( v -> {
208
- txObject . getConnectionHolder (). setTransactionActive ( true );
209
- Duration timeout = determineTimeout ( definition );
210
- if (! timeout . isNegative () && ! timeout . isZero ()) {
211
- txObject . getConnectionHolder (). setTimeoutInMillis ( timeout .toMillis ());
212
- }
213
- // Bind the connection holder to the thread.
214
- if ( txObject . isNewConnectionHolder ()) {
215
- synchronizationManager . bindResource ( obtainConnectionFactory (), txObject .getConnectionHolder ());
216
- }
217
- }). thenReturn ( con ). onErrorResume ( e -> {
218
- if ( txObject . isNewConnectionHolder ()) {
219
- return ConnectionFactoryUtils . releaseConnection ( con , obtainConnectionFactory ())
220
- . doOnTerminate (() -> txObject . setConnectionHolder ( null , false ))
221
- . then ( Mono . error ( e ));
222
- }
223
- return Mono . error ( e );
224
- } );
225
- }).onErrorResume (e -> {
206
+ return connectionMono .flatMap (con -> prepareTransactionalConnection ( con , definition , transaction )
207
+ .then (Mono .from (con .beginTransaction ()))
208
+ . then ( prepareTransactionalConnection ( con , definition ))
209
+ . doOnSuccess ( v -> {
210
+ txObject . getConnectionHolder (). setTransactionActive ( true );
211
+ Duration timeout = determineTimeout ( definition );
212
+ if (! timeout . isNegative () && ! timeout .isZero ()) {
213
+ txObject . getConnectionHolder (). setTimeoutInMillis ( timeout . toMillis ());
214
+ }
215
+ // Bind the connection holder to the thread.
216
+ if ( txObject .isNewConnectionHolder ()) {
217
+ synchronizationManager . bindResource ( obtainConnectionFactory (), txObject . getConnectionHolder ());
218
+ }
219
+ }). thenReturn ( con ). onErrorResume ( e -> {
220
+ if ( txObject . isNewConnectionHolder ()) {
221
+ return ConnectionFactoryUtils . releaseConnection ( con , obtainConnectionFactory ( ))
222
+ . doOnTerminate (() -> txObject . setConnectionHolder ( null , false ))
223
+ . then ( Mono . error ( e ));
224
+ }
225
+ return Mono . error ( e );
226
+ })) .onErrorResume (e -> {
226
227
CannotCreateTransactionException ex = new CannotCreateTransactionException (
227
228
"Could not open R2DBC Connection for transaction" , e );
228
229
return Mono .error (ex );
@@ -350,31 +351,17 @@ protected Mono<Void> doCleanupAfterCompletion(TransactionSynchronizationManager
350
351
}
351
352
352
353
/**
353
- * Prepare the transactional {@link Connection} right after transaction begin.
354
- * <p>The default implementation executes a "SET TRANSACTION READ ONLY" statement if the
355
- * {@link #setEnforceReadOnly "enforceReadOnly"} flag is set to {@code true} and the
356
- * transaction definition indicates a read-only transaction.
357
- * <p>The "SET TRANSACTION READ ONLY" is understood by Oracle, MySQL and Postgres
358
- * and may work with other databases as well. If you'd like to adapt this treatment,
359
- * override this method accordingly.
360
- * @param con the transactional R2DBC Connection
361
- * @param definition the current transaction definition
362
- * @param transaction the transaction object
363
- * @see #setEnforceReadOnly
354
+ * Prepare the transactional {@link Connection} right before transaction begin.
355
+ * @deprecated in favor of {@link #prepareTransactionalConnection(Connection, TransactionDefinition)}
356
+ * since this variant gets called too early (before transaction begin) for read-only customization
364
357
*/
358
+ @ Deprecated
365
359
protected Mono <Void > prepareTransactionalConnection (
366
360
Connection con , TransactionDefinition definition , Object transaction ) {
367
361
368
362
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject ) transaction ;
369
-
370
363
Mono <Void > prepare = Mono .empty ();
371
364
372
- if (isEnforceReadOnly () && definition .isReadOnly ()) {
373
- prepare = Mono .from (con .createStatement ("SET TRANSACTION READ ONLY" ).execute ())
374
- .flatMapMany (Result ::getRowsUpdated )
375
- .then ();
376
- }
377
-
378
365
// Apply specific isolation level, if any.
379
366
IsolationLevel isolationLevelToUse = resolveIsolationLevel (definition .getIsolationLevel ());
380
367
if (isolationLevelToUse != null && definition .getIsolationLevel () != TransactionDefinition .ISOLATION_DEFAULT ) {
@@ -404,6 +391,29 @@ protected Mono<Void> prepareTransactionalConnection(
404
391
return prepare ;
405
392
}
406
393
394
+ /**
395
+ * Prepare the transactional {@link Connection} right after transaction begin.
396
+ * <p>The default implementation executes a "SET TRANSACTION READ ONLY" statement if the
397
+ * {@link #setEnforceReadOnly "enforceReadOnly"} flag is set to {@code true} and the
398
+ * transaction definition indicates a read-only transaction.
399
+ * <p>The "SET TRANSACTION READ ONLY" is understood by Oracle, MySQL and Postgres
400
+ * and may work with other databases as well. If you'd like to adapt this treatment,
401
+ * override this method accordingly.
402
+ * @param con the transactional R2DBC Connection
403
+ * @param definition the current transaction definition
404
+ * @since 5.3.22
405
+ * @see #setEnforceReadOnly
406
+ */
407
+ protected Mono <Void > prepareTransactionalConnection (Connection con , TransactionDefinition definition ) {
408
+ Mono <Void > prepare = Mono .empty ();
409
+ if (isEnforceReadOnly () && definition .isReadOnly ()) {
410
+ prepare = Mono .from (con .createStatement ("SET TRANSACTION READ ONLY" ).execute ())
411
+ .flatMapMany (Result ::getRowsUpdated )
412
+ .then ();
413
+ }
414
+ return prepare ;
415
+ }
416
+
407
417
/**
408
418
* Resolve the {@linkplain TransactionDefinition#getIsolationLevel() isolation level constant} to a R2DBC
409
419
* {@link IsolationLevel}. If you'd like to extend isolation level translation for vendor-specific
0 commit comments