@@ -126,6 +126,8 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan
126126
127127 private boolean enforceReadOnly = false ;
128128
129+ private volatile @ Nullable Boolean defaultReadOnly ;
130+
129131
130132 /**
131133 * Create a new {@code DataSourceTransactionManager} instance.
@@ -270,13 +272,18 @@ protected void doBegin(Object transaction, TransactionDefinition definition) {
270272 if (logger .isDebugEnabled ()) {
271273 logger .debug ("Acquired Connection [" + newCon + "] for JDBC transaction" );
272274 }
275+ if (definition .isReadOnly ()) {
276+ checkDefaultReadOnly (newCon );
277+ }
273278 txObject .setConnectionHolder (new ConnectionHolder (newCon ), true );
274279 }
275280
276281 txObject .getConnectionHolder ().setSynchronizedWithTransaction (true );
277282 con = txObject .getConnectionHolder ().getConnection ();
278283
279- Integer previousIsolationLevel = DataSourceUtils .prepareConnectionForTransaction (con , definition );
284+ Integer previousIsolationLevel = DataSourceUtils .prepareConnectionForTransaction (con ,
285+ definition .getIsolationLevel (),
286+ (definition .isReadOnly () && !isDefaultReadOnly ()));
280287 txObject .setPreviousIsolationLevel (previousIsolationLevel );
281288 txObject .setReadOnly (definition .isReadOnly ());
282289
@@ -381,8 +388,9 @@ protected void doCleanupAfterCompletion(Object transaction) {
381388 if (txObject .isMustRestoreAutoCommit ()) {
382389 con .setAutoCommit (true );
383390 }
384- DataSourceUtils .resetConnectionAfterTransaction (
385- con , txObject .getPreviousIsolationLevel (), txObject .isReadOnly ());
391+ DataSourceUtils .resetConnectionAfterTransaction (con ,
392+ txObject .getPreviousIsolationLevel (),
393+ (txObject .isReadOnly () && !isDefaultReadOnly ()));
386394 }
387395 catch (Throwable ex ) {
388396 logger .debug ("Could not reset JDBC Connection after transaction" , ex );
@@ -399,6 +407,37 @@ protected void doCleanupAfterCompletion(Object transaction) {
399407 }
400408
401409
410+ /**
411+ * Check the default {@link Connection#isReadOnly()} flag on a freshly
412+ * obtained connection from the {@code DataSource}, assuming that the
413+ * same flag applies to all connections obtained from the given setup.
414+ * @param newCon the Connection to check
415+ * @since 6.2.13
416+ * @see #isDefaultReadOnly()
417+ */
418+ private void checkDefaultReadOnly (Connection newCon ) {
419+ if (this .defaultReadOnly == null ) {
420+ try {
421+ this .defaultReadOnly = newCon .isReadOnly ();
422+ }
423+ catch (Throwable ex ) {
424+ logger .debug ("Could not determine default JDBC Connection isReadOnly - assuming false" , ex );
425+ this .defaultReadOnly = false ;
426+ }
427+ }
428+ }
429+
430+ /**
431+ * Check whether the default read-only flag has been determined as {@code true},
432+ * assuming that all encountered connections will be read-only by default and
433+ * therefore do not need explicit {@link Connection#setReadOnly} (re)setting.
434+ * @since 6.2.13
435+ * @see #checkDefaultReadOnly(Connection)
436+ */
437+ private boolean isDefaultReadOnly () {
438+ return (this .defaultReadOnly == Boolean .TRUE );
439+ }
440+
402441 /**
403442 * Prepare the transactional {@code Connection} right after transaction begin.
404443 * <p>The default implementation executes a "SET TRANSACTION READ ONLY" statement
0 commit comments