diff --git a/src/main/java/org/apache/ibatis/jdbc/ScriptRunner.java b/src/main/java/org/apache/ibatis/jdbc/ScriptRunner.java index 0293b35c242..d1ba1957b33 100644 --- a/src/main/java/org/apache/ibatis/jdbc/ScriptRunner.java +++ b/src/main/java/org/apache/ibatis/jdbc/ScriptRunner.java @@ -120,8 +120,9 @@ public void runScript(Reader reader) { } else { executeLineByLine(reader); } - } finally { + } catch (RuntimeSqlException exception) { rollbackConnection(); + throw exception; } } diff --git a/src/test/java/org/apache/ibatis/jdbc/ScriptRunnerTest.java b/src/test/java/org/apache/ibatis/jdbc/ScriptRunnerTest.java index 3317c96471f..879754ee25f 100644 --- a/src/test/java/org/apache/ibatis/jdbc/ScriptRunnerTest.java +++ b/src/test/java/org/apache/ibatis/jdbc/ScriptRunnerTest.java @@ -16,7 +16,9 @@ package org.apache.ibatis.jdbc; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; @@ -282,4 +284,93 @@ void shouldAcceptMultiCharDelimiter() throws Exception { verify(stmt).execute("line 1;" + LINE_SEPARATOR + "line 2;" + LINE_SEPARATOR + LINE_SEPARATOR); verify(stmt).execute("line 3" + LINE_SEPARATOR); } + + @Test + void testRollbackWithAutoCommitFalseAndStopErrorTrue() throws Exception { + DataSource ds = createJPetstoreDataSource(); + try (Connection conn = ds.getConnection()) { + ScriptRunner runner = new ScriptRunner(conn); + runner.setAutoCommit(false); + runner.setStopOnError(true); + runner.setSendFullScript(false); + Reader reader = new StringReader(""" + INSERT INTO signon VALUES('xiaoai','123456'); + 123; + INSERT INTO signon VALUES('xiaolan','123456'); + """); + assertThrows(RuntimeSqlException.class, () -> runner.runScript(reader)); + } + assertSignonCountByUsername(ds, "xiaoai", 0L); + assertSignonCountByUsername(ds, "xiaolan", 0L); + } + + @Test + void testRollbackWithAutoCommitFalseAndStopErrorFalse() throws Exception { + DataSource ds = createJPetstoreDataSource(); + try (Connection conn = ds.getConnection()) { + ScriptRunner runner = new ScriptRunner(conn); + runner.setAutoCommit(false); + runner.setStopOnError(false); + runner.setSendFullScript(false); + Reader reader = new StringReader(""" + INSERT INTO signon VALUES('xiaoai','123456'); + 123; + INSERT INTO signon VALUES('xiaolan','123456'); + """); + runner.runScript(reader); + } + assertSignonCountByUsername(ds, "xiaoai", 1L); + assertSignonCountByUsername(ds, "xiaolan", 1L); + } + + private void assertSignonCountByUsername(DataSource dataSource, String username, long expectedVal) + throws SQLException { + try (Connection conn = dataSource.getConnection()) { + Map map = new SqlRunner(conn).selectOne("select count(*) as COUNT from signon where username = ?", + username); + assertNotNull(map); + assertNotNull(map.get("COUNT")); + assertEquals(expectedVal, map.get("COUNT")); + } + } + + @Test + void testRollbackWithAutoCommitTrueAndStopErrorTrue() throws Exception { + DataSource ds = createJPetstoreDataSource(); + try (Connection conn = ds.getConnection()) { + ScriptRunner runner = new ScriptRunner(conn); + runner.setAutoCommit(true); + runner.setStopOnError(true); + runner.setErrorLogWriter(null); + runner.setSendFullScript(false); + Reader reader = new StringReader(""" + INSERT INTO signon VALUES('xiaohong','123456'); + 123; + INSERT INTO signon VALUES('xiaoming','123456'); + """); + assertThrows(RuntimeSqlException.class, () -> runner.runScript(reader)); + } + assertSignonCountByUsername(ds, "xiaohong", 1L); + assertSignonCountByUsername(ds, "xiaoming", 0L); + } + + @Test + void testRollbackWithAutoCommitTrueAndStopErrorFalse() throws Exception { + DataSource ds = createJPetstoreDataSource(); + try (Connection conn = ds.getConnection()) { + ScriptRunner runner = new ScriptRunner(conn); + runner.setAutoCommit(true); + runner.setStopOnError(false); + runner.setErrorLogWriter(null); + runner.setSendFullScript(false); + Reader reader = new StringReader(""" + INSERT INTO signon VALUES('xiaohong','123456'); + 123; + INSERT INTO signon VALUES('xiaoming','123456'); + """); + runner.runScript(reader); + } + assertSignonCountByUsername(ds, "xiaohong", 1L); + assertSignonCountByUsername(ds, "xiaoming", 1L); + } }