Skip to content

Lazy handling of early setClientInfo/setNetworkTimeout calls in LazyConnectionDataSourceProxy - #37261

Draft
guanchengang wants to merge 4 commits into
spring-projects:mainfrom
guanchengang:gh37258
Draft

Lazy handling of early setClientInfo/setNetworkTimeout calls in LazyConnectionDataSourceProxy#37261
guanchengang wants to merge 4 commits into
spring-projects:mainfrom
guanchengang:gh37258

Conversation

@guanchengang

Copy link
Copy Markdown

Extend LazyConnectionInvocationHandler to cache early calls to:

  • setClientInfo(String, String)
  • setNetworkTimeout(Executor, int)

These methods now defer physical connection acquisition until Statement creation, consistent with existing lazy behavior for autoCommit, readOnly, transactionIsolation, catalog, and schema.

Accept and lazily cache calls to setNetworkTimeout even when the provided Executor is null. Since some JDBC driver implementations completely ignore the Executor parameter (or fall back to a default executor), we cannot meaningfully validate or handle a null Executor before the physical connection is obtained.

getClientInfo() and getClientInfo(String) remains non-lazy (triggers immediate connection fetch)because it is a read operation whose value cannot be reliably cached due to driver defaults, pooled connection remnants, or external session modifications.

setClientInfo(Properties) remains non-lazy. The reason is that JDBC driver implementations are inconsistent. Some treat it as overwrite, others as append/merge. To guarantee behavior identical to non-lazy execution across all driver, we choose not to cache or replay it, avoiding any risk of semantic mismatch.

Closes gh-37258

…onnectionDataSourceProxy

Extend LazyConnectionInvocationHandler to cache early calls to:
- setClientInfo(String, String)
- setNetworkTimeout(Executor, int)

These methods now defer physical connection acquisition until Statement
creation, consistent with existing lazy behavior for autoCommit, readOnly,
transactionIsolation, catalog, and schema.

Accept and lazily cache calls to setNetworkTimeout even when the provided
Executor is null. Since some JDBC driver implementations completely ignore the
Executor parameter (or fall back to a default executor), we cannot meaningfully
validate or handle a null Executor before the physical connection is obtained.

getClientInfo() and getClientInfo(String) remains non-lazy (triggers immediate
connection fetch)because it is a read operation whose value cannot be reliably
cached due to driver defaults, pooled connection remnants, or external session
modifications.

setClientInfo(Properties) remains non-lazy. The reason is that JDBC driver
implementations are inconsistent. Some treat it as overwrite, others as
append/merge. To guarantee behavior identical to non-lazy execution across
all driver, we choose not to cache or replay it, avoiding any risk of semantic
mismatch.

Closes spring-projectsgh-37258

Signed-off-by: Chengang Guan <guanchengang@qq.com>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Sep 9, 2026
@sbrannen sbrannen added in: data Issues in data modules (jdbc, orm, oxm, tx) type: enhancement A general enhancement labels Sep 9, 2026
@sbrannen sbrannen self-assigned this Sep 9, 2026
@sbrannen
sbrannen marked this pull request as draft September 9, 2026 08:41
@sbrannen sbrannen added this to the 7.0.10 milestone Sep 9, 2026
Signed-off-by: Chengang Guan <guanchengang@qq.com>

@sbrannen sbrannen left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

I've requested a few changes and have a question.

Accept and lazily cache calls to setNetworkTimeout even when the provided Executor is null. Since some JDBC driver implementations completely ignore the Executor parameter (or fall back to a default executor), we cannot meaningfully validate or handle a null Executor before the physical connection is obtained.

The Javadoc for java.sql.Connection.setNetworkTimeout(Executor, int) explicitly states that it will throw a java.sql.SQLException if "the executor is null". So, are you claiming that a java.sqlConnection returned from LazyConnectionDataSourceProxy.getConnection(String, String) should not comply with the contract of the JDBC specification? In other words, shouldn't we rather eagerly throw an SQLException for a null Executor?

In any case, please add tests for the null Executor use case.

Once you've addressed these issues I'll take another look.

Cheers,

Sam

@sbrannen sbrannen added status: waiting-for-feedback We need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Sep 9, 2026
@sbrannen

sbrannen commented Sep 9, 2026

Copy link
Copy Markdown
Member

I also noticed that the Javadoc should be updated. The current wording only mentions auto-commit mode, transaction isolation, and read-only mode:

Connection initialization properties like auto-commit mode, transaction isolation and read-only mode will be kept and applied to the actual JDBC Connection as soon as an actual Connection is fetched (if ever).

That sentence is already outdated. It doesn't mention catalog, schema, or holdability, which were added in 6.1.2, and this PR now adds two more deferred properties (client info and network timeout).

So, please update the class-level Javadoc by enumerating all of the deferred properties there and explicitly calling out setClientInfo(Properties), getClientInfo(), and getClientInfo(String) as the exceptions that force immediate acquisition of the physical Connection. That way users can rely on the Javadoc to know what's actually lazy instead of having to read the implementation.

@guanchengang

Copy link
Copy Markdown
Author

The Javadoc for java.sql.Connection.setNetworkTimeout(Executor, int) explicitly states that it will throw a java.sql.SQLException if "the executor is null". So, are you claiming that a java.sqlConnection returned from LazyConnectionDataSourceProxy.getConnection(String, String) should not comply with the contract of the JDBC specification? In other words, shouldn't we rather eagerly throw an SQLException for a null Executor?

I did notice that the spec explicitly says null Executor should throw SQLException. However, after looking into how various JDBC drivers actually implement this method, I found that behavior is inconsistent:

  • Some drivers strictly follow the spec and throw an exception when Executor is null.
  • But others (like PostgreSQL and SQL Server) completely ignore the Executor parameter and simply set the socket timeout without using the provided Executor at all.

If we eagerly throw an SQLException at the proxy layer for a null Executor, we would be introducing inconsistent behavior compared to using a non-lazy connection directly. A user would get an exception when using LazyConnectionDataSourceProxy, but the same code would work fine against the raw physical connection from those drivers.

To maintain behavioral consistency between lazy and non-lazy usage, I think it's more reasonable to cache the call lazily and defer the exception (if any) to the underlying physical connection. This way, the actual driver decides whether to throw or ignore, and we don't break users who rely on drivers that accept null.

What are your thoughts?

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 9, 2026
Signed-off-by: Chengang Guan <guanchengang@qq.com>
@guanchengang

Copy link
Copy Markdown
Author

Thanks for the review. I’ve updated the PR based on all your suggestions, with the exception of the setNetworkTimeout part. I believe we should discuss that further before making a change.

Actually, the behavior of setNetworkTimeout is now consistent with that of setHoldability and setTransactionIsolation. When an out-of-range value is set on the LazyConnection returned by our proxy, such as setTransactionIsolation(1000), the exception is likewise deferred until the actual Connection is fetched.

Looking forward to your thoughts.

@sbrannen sbrannen left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making the requested changes. This looks a lot better now.

I've requested a few minor changes regarding spacing and diction.

* is fetched (if ever). Consequently, commit and rollback calls will be ignored
* if no Statements have been created.
*
* <p>Once a properties has been set, the corresponding getter method returns the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* <p>Once a properties has been set, the corresponding getter method returns the
* <p>Once a property has been set, the corresponding getter method returns the

Comment on lines +132 to +133
verify(physicalConnection1,never()).setCatalog("catalogName");
verify(physicalConnection1,never()).getCatalog();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
verify(physicalConnection1,never()).setCatalog("catalogName");
verify(physicalConnection1,never()).getCatalog();
verify(physicalConnection1, never()).setCatalog("catalogName");
verify(physicalConnection1, never()).getCatalog();

Please apply spacing consistently throughout the tests.

* driver defaults, remnants from pooled connections, or external session
* modifications.
*
* <p>The{@link java.sql.Connection#setClientInfo(java.util.Properties)}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* <p>The{@link java.sql.Connection#setClientInfo(java.util.Properties)}
* <p>The {@link java.sql.Connection#setClientInfo(java.util.Properties)}

@sbrannen sbrannen added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Sep 10, 2026
Signed-off-by: Chengang Guan <guanchengang@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

in: data Issues in data modules (jdbc, orm, oxm, tx) status: waiting-for-feedback We need additional information before we can continue type: enhancement A general enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lazy handling of early setClientInfo/setNetworkTimeout calls in LazyConnectionDataSourceProxy

3 participants