From cc5ae239156bb9553263b3a825fb34dfeb5f5265 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 5 Apr 2025 16:03:31 +0200 Subject: [PATCH] Suppress rollback attempt in case of timeout (connection closed) Closes gh-34714 --- .../LazyConnectionDataSourceProxy.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.java b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.java index 38cd26a6272..dc02cd98954 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 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. @@ -77,6 +77,9 @@ import org.springframework.util.Assert; * You will get the same effect with non-transactional reads, but lazy fetching * of JDBC Connections allows you to still perform reads in transactions. * + *

As of 6.2.6, this DataSource proxy also suppresses a rollback attempt + * in case of a timeout where the connection has been closed in the meantime. + * *

NOTE: This DataSource proxy needs to return wrapped Connections * (which implement the {@link ConnectionProxy} interface) in order to handle * lazy fetching of an actual JDBC Connection. Use {@link Connection#unwrap} @@ -436,11 +439,19 @@ public class LazyConnectionDataSourceProxy extends DelegatingDataSource { return null; } - // Target Connection already fetched, - // or target Connection necessary for current operation -> - // invoke method on target connection. + + // Target Connection already fetched, or target Connection necessary for current operation + // -> invoke method on target connection. try { - return method.invoke(getTargetConnection(method), args); + Connection conToUse = getTargetConnection(method); + + if ("rollback".equals(method.getName()) && conToUse.isClosed()) { + // Connection closed in the meantime, probably due to a resource timeout. Since a + // rollback attempt typically happens right before close, we leniently suppress it. + return null; + } + + return method.invoke(conToUse, args); } catch (InvocationTargetException ex) { throw ex.getTargetException();