Details
-
Bug
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
1.5.6
-
None
Description
Transaction isolation level set via Connection#setTransactionIsolation is lost,
when statement are executed on such a connection that trigger an MaxAllowedPacketException.
Although the connection is still usable, it silently switches back to the default isolation behaviour,
Testcase:
public class IsolationLevelLostOnReconnect { |
|
@Test |
public void isolationLevelResets() throws SQLException { |
try (Connection c = DriverManager.getConnection("jdbc:mariadb://localhost:3306/test", "test", "test")) { |
long max = maxPacket(c); |
if (max > Integer.MAX_VALUE - 10) { |
fail("max_allowed_packet to high for this test"); |
}
|
c.prepareStatement("create table if not exists foo (x longblob)").execute(); |
c.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
|
assertThat(level(c), is("READ-UNCOMMITTED")); |
try (PreparedStatement st = c.prepareStatement("insert into foo (?)")) { |
st.setBytes(1, data((int) (max + 10))); |
st.execute();
|
fail();
|
} catch (SQLException e) { |
assertThat(e.getMessage(), containsString("max_allowed_packet")); |
// we still have a working connection |
assertThat(maxPacket(c), is(max));
|
// but our isolation level changed: |
assertThat(level(c), is("READ-UNCOMMITTED")); |
}
|
}
|
}
|
|
private String level(Connection c) throws SQLException { |
try (ResultSet rs = c.prepareStatement("select @@tx_isolation").executeQuery()) { |
rs.next();
|
return rs.getString(1); |
}
|
}
|
|
private long maxPacket(Connection c) throws SQLException { |
try (ResultSet rs = c.prepareStatement("select @@max_allowed_packet").executeQuery()) { |
rs.next();
|
return rs.getLong(1); |
}
|
}
|
|
private byte[] data(int size) { |
byte[] data = new byte[size]; |
Arrays.fill(data, (byte) 'a'); |
return data; |
}
|
}
|
Javadoc on Connection#setTransactionIsolation reads (excerpt):
* Attempts to change the transaction isolation level for this |
* <code>Connection</code> object to the one given.
|
Clearly, this does not hold in this situation.
Attachments
Activity
Field | Original Value | New Value |
---|---|---|
Description |
Transaction isolation level set via {{Connection#setTransactionIsolation}} is lost,
when statement are executed on such a connection that trigger an MaxAllowedPacketException. Although the connection is still usable, it silently switches back to the default isolation behaviour, Testcase: {code} public class IsolationLevelLostOnReconnect { @Test public void isolationLevelResets() throws SQLException { try (Connection c = DriverManager.getConnection("jdbc:mariadb://localhost:3306/test", "test", "test")) { long max = maxPacket(c); if (max > Integer.MAX_VALUE - 10) { fail("max_allowed_packet to high for this test"); } c.prepareStatement("create table if not exists foo (x longblob)").execute(); c.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); assertThat(level(c), is("READ-UNCOMMITTED")); try (PreparedStatement st = c.prepareStatement("insert into foo (?)")) { st.setBytes(1, data((int) (max + 10))); st.execute(); fail(); } catch (SQLException e) { assertThat(e.getMessage(), containsString("max_allowed_packet")); // we still have a working connection assertThat(maxPacket(c), is(max)); // but our isolation level changed: assertThat(level(c), is("READ-UNCOMMITTED")); } } } private String level(Connection c) throws SQLException { try (ResultSet rs = c.prepareStatement("select @@tx_isolation").executeQuery()) { rs.next(); return rs.getString(1); } } private long maxPacket(Connection c) throws SQLException { try (ResultSet rs = c.prepareStatement("select @@max_allowed_packet").executeQuery()) { rs.next(); return rs.getLong(1); } } private byte[] data(int size) { byte[] data = new byte[size]; Arrays.fill(data, (byte) 'a'); return data; } } {code} Javadoc on {{Connection#setTransactionIsolation}} reads (excerpt): {code} * Attempts to change the transaction isolation level for this * <code>Connection</code> object to the one given. {code} Clearly, this does not hold in this situation. |
Transaction isolation level set via {{Connection#setTransactionIsolation}} is lost,
when statement are executed on such a connection that trigger an MaxAllowedPacketException. Although the connection is still usable, it silently switches back to the default isolation behaviour, Testcase: {code:java} public class IsolationLevelLostOnReconnect { @Test public void isolationLevelResets() throws SQLException { try (Connection c = DriverManager.getConnection("jdbc:mariadb://localhost:3306/test", "test", "test")) { long max = maxPacket(c); if (max > Integer.MAX_VALUE - 10) { fail("max_allowed_packet to high for this test"); } c.prepareStatement("create table if not exists foo (x longblob)").execute(); c.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); assertThat(level(c), is("READ-UNCOMMITTED")); try (PreparedStatement st = c.prepareStatement("insert into foo (?)")) { st.setBytes(1, data((int) (max + 10))); st.execute(); fail(); } catch (SQLException e) { assertThat(e.getMessage(), containsString("max_allowed_packet")); // we still have a working connection assertThat(maxPacket(c), is(max)); // but our isolation level changed: assertThat(level(c), is("READ-UNCOMMITTED")); } } } private String level(Connection c) throws SQLException { try (ResultSet rs = c.prepareStatement("select @@tx_isolation").executeQuery()) { rs.next(); return rs.getString(1); } } private long maxPacket(Connection c) throws SQLException { try (ResultSet rs = c.prepareStatement("select @@max_allowed_packet").executeQuery()) { rs.next(); return rs.getLong(1); } } private byte[] data(int size) { byte[] data = new byte[size]; Arrays.fill(data, (byte) 'a'); return data; } } {code} Javadoc on {{Connection#setTransactionIsolation}} reads (excerpt): {code:java} * Attempts to change the transaction isolation level for this * <code>Connection</code> object to the one given. {code} Clearly, this does not hold in this situation. |
Attachment | IsolationLevelLostOnReconnect.java [ 43201 ] |
Fix Version/s | 1.6.0 [ 22119 ] |
Fix Version/s | 1.5.7 [ 22500 ] | |
Fix Version/s | 1.6.0 [ 22119 ] |
Status | Open [ 1 ] | In Progress [ 3 ] |
Resolution | Fixed [ 1 ] | |
Status | In Progress [ 3 ] | Closed [ 6 ] |
Workflow | MariaDB v3 [ 79115 ] | MariaDB v4 [ 134941 ] |
The following patch fixes the test case by ensuring non-default isolation levels are applied again upon reconnecting.
diff --git a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java
index 95fd170..88c6445 100644
--- a/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java
+++ b/src/main/java/org/mariadb/jdbc/internal/protocol/AbstractConnectProtocol.java
@@ -451,6 +451,9 @@ public abstract class AbstractConnectProtocol implements Protocol {
sessionOption += "," + options.sessionVariables;
}
executeQuery("set session " + sessionOption);
+ if (getTransactionIsolationLevel() != 0) {
+ setTransactionIsolation(getTransactionIsolationLevel());
+ }
}
private void handleConnectionPhases() throws QueryException {
I did run mvn test locally and there were no differences in the outcome (severel tests failed and several skipped, I assume because of my environment).