[CONJ-407] Connection.setTransactionIsolation lost on MaxAllowedPacketException Created: 2017-01-06  Updated: 2017-01-12  Resolved: 2017-01-12

Status: Closed
Project: MariaDB Connector/J
Component/s: Other
Affects Version/s: 1.5.6
Fix Version/s: 1.5.7

Type: Bug Priority: Major
Reporter: Matthias Pretzer Assignee: Diego Dupin
Resolution: Fixed Votes: 0
Labels: None

Attachments: Java Source File IsolationLevelLostOnReconnect.java    

 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.



 Comments   
Comment by Matthias Pretzer [ 2017-01-07 ]

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).

Comment by Diego Dupin [ 2017-01-09 ]

right, failover will have the same issue.

Generated at Thu Feb 08 03:15:26 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.