AbstractJdbc4Connection.isValid() should not mark the transaction as started #214
Comments
On 11/17/2014 04:40 PM, cowwoc wrote:
I agree, that's clearly a bug. We should be sending an empty string query (""), or preferably just I don't expect to have time to do anything about this any time soon Craig Ringer http://www.2ndQuadrant.com/ |
That flies in the face of all existing connection pool implementations. What do you expect them to do instead? |
On 11/17/2014 04:47 PM, cowwoc wrote:
For connection pools it's reasonable, as it lets them fail-fast. A That's about the only generally reasonable use of I routinely see people trying to write code along this pattern:
which is a hopeless race condition, as the connection can fail in between the test and actual use of it, or partway through using it. The correct thing to do is generally do do everything in a retry loop with error-specific logic and a random backoff delay on retries, something closer to the pseudo-Java:
Yes, unfortunately that's much more complicated. PgJDBC could make this easier for users by adding support for the JDBC4 It's unfortunate that apps need to incorporate this kind of logic, and Craig Ringer http://www.2ndQuadrant.com/ |
Anyway, the point is: I agree that the behaviour you describe is a bug. I don't expect to have time to work on it any time soon. If you want to submit a patch, which would be very welcome, I suggest that you:
This may not be the best approach, as I haven't looked into it in detail, it's just where I'd start looking. |
Try this workaround, set HikariCP |
Currently the driver does a "select 1" I don't really see how it is Dave Cramer On 17 November 2014 04:22, Brett Wooldridge notifications@github.com
|
On 11/17/2014 07:13 PM, Dave Cramer wrote:
Autocommit shouldn't matter, I think that's the point. It should run Craig Ringer http://www.2ndQuadrant.com/ |
@brettwooldridge According to brettwooldridge/HikariCP#196 setting @davecramer Yes, autocommit is off but as @ringerc stated it shouldn't matter. |
@brettwooldridge and @ringerc I've updated http://stackoverflow.com/a/17960047/14731 based on your recommendations. Please let me know if I've missed anything. |
On 11/18/2014 01:49 AM, cowwoc wrote:
Yes, or more specifically, I think that the current behaviour described, Craig Ringer http://www.2ndQuadrant.com/ |
Actually, by definition isValid, if executed while a transaction is in progress, will affect its state since the query that is sent is executed in the context of said transaction just like any other user query. https://docs.oracle.com/javase/6/docs/api/java/sql/Connection.html#isValid(int) The issue here is that the pool must return a known good connection but must first ensure that when it does so that the current session is not in transaction. Ideally isValid would be aware enough of its state to know whether it needs to issue a commit after sending the heartbeat query. It needs to read the session and confirm in or out of transaction before sending the heartbeat query and issue commit as appropriate once the query result returns. The locking involved with the issuance of "select 1" versus some other query warrants discussion - even if we'd frown upon mid-transaction calls to isValid - but falls outside the scope of this report and the failure of isValid to leave the connection in the same transaction state it started with. |
On 11/18/2014 01:00 PM, David Johnston wrote:
Yes, but what about autocommit state? If autocommit is off, isValid() shouldn't be opening a new transaction, It must round-trip to the server to ensure it's alive, but it shouldn't That's why I think that for PostgreSQL we should be sending a Sync It'd be good to see what the spec says and what other drivers do in this
It's actually directly relevant, as only some commands will acquire a We can send a Sync message or an empty string without affecting the Craig Ringer http://www.2ndQuadrant.com/ |
@ringerc In my opinion, the isValid() call should do the minimum required to determine that the connection is "live". If this can be done without running a query that would initiate a transaction that would be great. From my experience, MySQL does not initiate a transaction, but rather sends (literally) the String But HikariCP does have a "backdoor" for drivers that do initiate transactions from isValid() or test queries, and that is to define an explicit query (which disables the isValid() check), and set |
Seems simple enough then, we can change the current code to do select "" Dave Cramer On 18 November 2014 00:35, Brett Wooldridge notifications@github.com
|
On 11/18/2014 06:52 PM, Dave Cramer wrote:
would have the same issue. It'd have to send the empty string as a query. No SELECT. IIRC PgJDBC might not actually send such queries to the server at the Craig Ringer http://www.2ndQuadrant.com/ |
Connection.isValid() should have no impact on transaction state See issue #214 for details.
Hikari connection pool invokes
AbstractJdbc4Connection.isValid()
before handing out a new connection.AbstractJdbc4Connection.isValid()
ends up triggeringQueryExecutorImpl.receiveRFQ:2270
which sets the transaction state toProtocolConnection.TRANSACTION_OPEN
. Subsequent calls toConnection.setTransactionIsolation()
fail withCannot change transaction isolation level in the middle of a transaction.
I don't think the specification meant to imply that invoking
Connection.isValid()
starts the transaction, thereby preventing users from invokingsetTransactionIsolation()
. I don't think it is the connection pool's responsibility tocommit()
orrollback()
a transaction after invokingConnection.isValid()
. I am not aware of any other database that behaves this way.Expected behavior: transaction state should not be affected by call to
AbstractJdbc4Connection.isValid()
The text was updated successfully, but these errors were encountered: