@@ -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.
@@ -269,13 +271,18 @@ protected void doBegin(Object transaction, TransactionDefinition definition) {
269271 if (logger .isDebugEnabled ()) {
270272 logger .debug ("Acquired Connection [" + newCon + "] for JDBC transaction" );
271273 }
274+ if (definition .isReadOnly ()) {
275+ checkDefaultReadOnly (newCon );
276+ }
272277 txObject .setConnectionHolder (new ConnectionHolder (newCon ), true );
273278 }
274279
275280 txObject .getConnectionHolder ().setSynchronizedWithTransaction (true );
276281 con = txObject .getConnectionHolder ().getConnection ();
277282
278- Integer previousIsolationLevel = DataSourceUtils .prepareConnectionForTransaction (con , definition );
283+ Integer previousIsolationLevel = DataSourceUtils .prepareConnectionForTransaction (con ,
284+ definition .getIsolationLevel (),
285+ (definition .isReadOnly () && !isDefaultReadOnly ()));
279286 txObject .setPreviousIsolationLevel (previousIsolationLevel );
280287 txObject .setReadOnly (definition .isReadOnly ());
281288
@@ -380,8 +387,9 @@ protected void doCleanupAfterCompletion(Object transaction) {
380387 if (txObject .isMustRestoreAutoCommit ()) {
381388 con .setAutoCommit (true );
382389 }
383- DataSourceUtils .resetConnectionAfterTransaction (
384- con , txObject .getPreviousIsolationLevel (), txObject .isReadOnly ());
390+ DataSourceUtils .resetConnectionAfterTransaction (con ,
391+ txObject .getPreviousIsolationLevel (),
392+ (txObject .isReadOnly () && !isDefaultReadOnly ()));
385393 }
386394 catch (Throwable ex ) {
387395 logger .debug ("Could not reset JDBC Connection after transaction" , ex );
@@ -398,6 +406,37 @@ protected void doCleanupAfterCompletion(Object transaction) {
398406 }
399407
400408
409+ /**
410+ * Check the default {@link Connection#isReadOnly()} flag on a freshly
411+ * obtained connection from the {@code DataSource}, assuming that the
412+ * same flag applies to all connections obtained from the given setup.
413+ * @param newCon the Connection to check
414+ * @since 6.2.13
415+ * @see #isDefaultReadOnly()
416+ */
417+ private void checkDefaultReadOnly (Connection newCon ) {
418+ if (this .defaultReadOnly == null ) {
419+ try {
420+ this .defaultReadOnly = newCon .isReadOnly ();
421+ }
422+ catch (Throwable ex ) {
423+ logger .debug ("Could not determine default JDBC Connection isReadOnly - assuming false" , ex );
424+ this .defaultReadOnly = false ;
425+ }
426+ }
427+ }
428+
429+ /**
430+ * Check whether the default read-only flag has been determined as {@code true},
431+ * assuming that all encountered connections will be read-only by default and
432+ * therefore do not need explicit {@link Connection#setReadOnly} (re)setting.
433+ * @since 6.2.13
434+ * @see #checkDefaultReadOnly(Connection)
435+ */
436+ private boolean isDefaultReadOnly () {
437+ return (this .defaultReadOnly == Boolean .TRUE );
438+ }
439+
401440 /**
402441 * Prepare the transactional {@code Connection} right after transaction begin.
403442 * <p>The default implementation executes a "SET TRANSACTION READ ONLY" statement
0 commit comments