Bug #116318 | useServerPrepStmts useLocalTransactionState cause first execute rollback failure | ||
---|---|---|---|
Submitted: | 9 Oct 2024 3:34 | Modified: | 19 Dec 2024 1:38 |
Reporter: | kang wang | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | Connector / J | Severity: | S2 (Serious) |
Version: | 9.0.0 | OS: | Any |
Assigned to: | CPU Architecture: | Any |
[9 Oct 2024 3:34]
kang wang
[9 Oct 2024 6:26]
kang wang
If I set any of useServerPrepStmts and useLocalTransactionState to true, I can successfully roll back the first time the project is started.
[9 Oct 2024 8:13]
MySQL Verification Team
Hello kang wang, Thank you for the report and test case. regards, Umesh
[4 Dec 2024 19:00]
Axyoan Marcelo
Posted by developer: Hello kang wang, Could you clarify what is the issue you are facing? I interpreted your report as "When setting useServerPrepStmts and useLocalTransactionState to true, the first rollback fails, but subsequent rollbacks are successful" I ran the testcase you provided but couldn't find any bug so I wanted to know if there's something I'm missing or if I misunderstood your report. Thank you for your report Regards, Axyoan
[6 Dec 2024 11:18]
kang wang
Sorry for the inconvenience, I’ve updated my code. The issue I’m currently facing is that in version 9.0.0, all inserts into cfg_user are successful, but when inserting into cfg_telephone, the operation correctly throws an exception. This indicates that the transaction is not being applied effectively. sql: CREATE TABLE `cfg_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `age` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- Create telephone table with unique constraint on phone number CREATE TABLE `cfg_telephone` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `phone` varchar(20) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_phone` (`phone`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; code: public class MySQLTransactionTest { private static final String JDBC_URL = "jdbc:mysql://localhost:3306/test_db?useSSL=false&useServerPrepStmts=true&useLocalTransactionState=true"; private static final String USERNAME = "your_username"; private static final String PASSWORD = "your_password"; @Test void testTransactionRollback() { try { for (int i = 0; i < 5; i++) { final Connection conn = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); conn.setAutoCommit(false); doInsertOneByOne(conn); conn.setAutoCommit(true); // After this point, the data is actually committed conn.close(); } } catch (Exception e) { e.printStackTrace(); } } @Test void testTransactionRollbackBatch() { try { for (int i = 0; i < 5; i++) { final Connection conn = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); conn.setAutoCommit(false); doInsertBatch(conn); conn.setAutoCommit(true); conn.close(); } } catch (Exception e) { e.printStackTrace(); } } private void doInsertBatch(Connection conn) throws SQLException { try (PreparedStatement st = conn.prepareStatement("insert into cfg_user(name, age) values(?, ?)")) { // First insert st.setString(1, "cfg"); st.setInt(2, 18); st.addBatch(); // Second insert (insert phone to trigger error) PreparedStatement st2 = conn.prepareStatement("insert into cfg_telephone(phone) values(?)"); st2.setString(1, "17612176673"); st2.executeUpdate(); st.executeBatch(); conn.commit(); // This line will not be reached } catch (Exception e) { e.printStackTrace(); conn.rollback(); // This rollback will actually fail } } private void doInsertOneByOne(Connection conn) throws SQLException { try { // Insert user PreparedStatement st1 = conn.prepareStatement("insert into cfg_user(name, age) values(?, ?)"); st1.setString(1, "cfg"); st1.setInt(2, 18); st1.executeUpdate(); // Insert phone (trigger error) PreparedStatement st2 = conn.prepareStatement("insert into cfg_telephone(phone) values(?)"); st2.setString(1, "17612176673"); st2.executeUpdate(); conn.commit(); // This line will not be reached } catch (Exception e) { e.printStackTrace(); conn.rollback(); // This rollback will actually fail } } }
[10 Dec 2024 16:00]
Axyoan Marcelo
Posted by developer: Hello kang wang, Thank you for the information, I can confirm I see the behavior you are describing. This is definitely a bug. Once again, thank you for your report Regards, Axyoan
[19 Dec 2024 1:38]
Daniel So
Posted by developer: Added the following entry to the Connector/J 9.1.2 changelog: "When the connection properties useServerPrepStmts and useLocalTransactionState were both true and a PreparedStatement was used, a statement rollback would fail. This was because the PreparedStatement always reset the local transaction state. With this fix, Connector/J checks and makes sure that the transaction state is only reset when it should be."