There is method for flushing(executing) batch update statements that stored in a JDBC driver class at any timing. This method can be used when you use the ExecutorType.BATCH as ExecutorType.
flushStatements()]]>
-
Métodos de control de transacción
+
Métodos de control de transacción
El parámetro ResultContext te da acceso al objeto resultado en sí mismo, un contador del número de objetos creados y un método booleano stop() que te permite indicar a MyBatis que pare la carga de datos.
Por defecto MyBatis no hace un commit a no ser que haya detectado que la base de datos ha sido modificada por una insert, update o delete. Si has realizado cambios sin llamar a estos métodos, entonces puedes pasar true en al método de commit() y rollback() para asegurar que se realiza el commit (ten en cuenta que aun así no puedes forzar el commit() en modo auto-commit o cuando se usa un gestor de transacciones externo). La mayoría de las veces no tendrás que llamar a rollback() dado que MyBatis lo hará por ti en caso de que no hayas llamado a commit(). Sin embargo, si necesitas un control más fino sobre la sesión, donde puede que haya varios commits, tienes esta opción para hacerlo posible.
+
Por defecto MyBatis no hace un commit a no ser que haya detectado que la base de datos ha sido modificada por una insert, update, delete o select con affectData habilitado. Si has realizado cambios sin llamar a estos métodos, entonces puedes pasar true en al método de commit() y rollback() para asegurar que se realiza el commit (ten en cuenta que aun así no puedes forzar el commit() en modo auto-commit o cuando se usa un gestor de transacciones externo). La mayoría de las veces no tendrás que llamar a rollback() dado que MyBatis lo hará por ti en caso de que no hayas llamado a commit(). Sin embargo, si necesitas un control más fino sobre la sesión, donde puede que haya varios commits, tienes esta opción para hacerlo posible.
NOTA MyBatis-Spring y MyBatis-Guice proporcionan gestión de transacción declarativa. Por tanto si estás usando MyBatis con Spring o Guice consulta sus manuales específicos.
Set this to true when writing a INSERT, UPDATE or DELETE statement that returns data so that the transaction is controlled properly. Also see Transaction Control Method. Default: false (since 3.5.12)
+
+
@@ -405,6 +410,18 @@ Por ejemplo, si la columna id de la tabla Author del ejemplo siguiente fuera aut
+
+
+ As an irregular case, some databases allow INSERT, UPDATE or DELETE statement to return result set (e.g. RETURNING clause of PostgreSQL and MariaDB or OUTPUT clause of MS SQL Server). This type of statement must be written as ]]> to map the returned data.
+
기본적으로 마이바티스는 insert, update 또는 delete 를 호출하여 데이터베이스가 변경된 것으로 감지하지 않는 한 실제로 커밋하지 않는다.
+
기본적으로 마이바티스는 insert, update, delete 또는 affectData가 활성화된select 를 호출하여 데이터베이스가 변경된 것으로 감지하지 않는 한 실제로 커밋하지 않는다.
이러한 메소드 호출없이 변경되면 커밋된 것으로 보장하기 위해 commit 와 rollback 메소드에 true 값을 전달한다.
참고 MyBatis-Spring 과 MyBatis-Guice는 선언적인 트랜잭션 관리기법을 제공한다.
그래서 스프링이나 쥬스와 함께 마이바티스를 사용한다면 해당되는 메뉴얼을 꼭 참고하길 바란다.
diff --git a/src/site/ko/xdoc/sqlmap-xml.xml b/src/site/ko/xdoc/sqlmap-xml.xml
index 70a6615a425..4ddde0df518 100644
--- a/src/site/ko/xdoc/sqlmap-xml.xml
+++ b/src/site/ko/xdoc/sqlmap-xml.xml
@@ -188,6 +188,11 @@ ps.setInt(1,id);]]>
디폴트값은 false 이다.
+
+
affectData
+
Set this to true when writing a INSERT, UPDATE or DELETE statement that returns data so that the transaction is controlled properly. Also see Transaction Control Method. Default: false (since 3.5.12)
+
+
@@ -392,6 +397,18 @@ ps.setInt(1,id);]]>
+
+
+ As an irregular case, some databases allow INSERT, UPDATE or DELETE statement to return result set (e.g. RETURNING clause of PostgreSQL and MariaDB or OUTPUT clause of MS SQL Server). This type of statement must be written as ]]> to map the returned data.
+
There is method for flushing (executing) batch update statements that are stored in a JDBC driver class at any time. This method can be used when the ExecutorType is ExecutorType.BATCH.
flushStatements()]]>
-
Transaction Control Methods
+
Transaction Control Methods
There are four methods for controlling the scope of a transaction. Of course, these have no effect if you've chosen to use auto-commit or if you're using an external transaction manager. However, if you're using the JDBC transaction manager, managed by the Connection instance, then the four methods that will come in handy are:
By default MyBatis does not actually commit unless it detects that the database has been changed by a call to insert, update or delete. If you've somehow made changes without calling these methods, then you can pass true into the commit and rollback methods to guarantee that they will be committed (note, you still can't force a session in auto-commit mode, or one that is using an external transaction manager). Most of the time you won't have to call rollback(), as MyBatis will do that for you if you don't call commit. However, if you need more fine-grained control over a session where multiple commits and rollbacks are possible, you have the rollback option there to make that possible.
+
By default MyBatis does not actually commit unless it detects that the database has been changed by a call to insert, update, delete or select with affectData enabled. If you've somehow made changes without calling these methods, then you can pass true into the commit and rollback methods to guarantee that they will be committed (note, you still can't force a session in auto-commit mode, or one that is using an external transaction manager). Most of the time you won't have to call rollback(), as MyBatis will do that for you if you don't call commit. However, if you need more fine-grained control over a session where multiple commits and rollbacks are possible, you have the rollback option there to make that possible.
NOTE MyBatis-Spring and MyBatis-Guice provide declarative transaction handling. So if you are using MyBatis with Spring or Guice please refer to their specific manuals.
Local Cache
diff --git a/src/site/xdoc/sqlmap-xml.xml b/src/site/xdoc/sqlmap-xml.xml
index 7ba060720c4..21332e04a5a 100644
--- a/src/site/xdoc/sqlmap-xml.xml
+++ b/src/site/xdoc/sqlmap-xml.xml
@@ -245,6 +245,11 @@ ps.setInt(1,id);]]>
be returned by the statement and gives a name to each one. Names are separated by commas.
+
+
affectData
+
Set this to true when writing a INSERT, UPDATE or DELETE statement that returns data so that the transaction is controlled properly. Also see Transaction Control Method. Default: false (since 3.5.12)
+
+
@@ -491,6 +496,18 @@ ps.setInt(1,id);]]>
+
+
+ As an irregular case, some databases allow INSERT, UPDATE or DELETE statement to return result set (e.g. RETURNING clause of PostgreSQL and MariaDB or OUTPUT clause of MS SQL Server). This type of statement must be written as ]]> to map the returned data.
+
Set this to true when writing a INSERT, UPDATE or DELETE statement that returns data so that the transaction is controlled properly. Also see Transaction Control Method. Default: false (since 3.5.12)
+
+
@@ -461,6 +466,18 @@ ps.setInt(1,id);]]>
+
+
+ As an irregular case, some databases allow INSERT, UPDATE or DELETE statement to return result set (e.g. RETURNING clause of PostgreSQL and MariaDB or OUTPUT clause of MS SQL Server). This type of statement must be written as ]]> to map the returned data.
+
+
+
+ insert into Author (username, password, email, bio)
+ values (#{username}, #{password}, #{email}, #{bio})
+ returning id, username, password, email, bio
+]]>
+
diff --git a/src/test/java/org/apache/ibatis/submitted/dirty_select/DirtySelectTest.java b/src/test/java/org/apache/ibatis/submitted/dirty_select/DirtySelectTest.java
new file mode 100644
index 00000000000..64d6cd31a50
--- /dev/null
+++ b/src/test/java/org/apache/ibatis/submitted/dirty_select/DirtySelectTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2009-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ibatis.submitted.dirty_select;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.Iterator;
+
+import org.apache.ibatis.BaseDataTest;
+import org.apache.ibatis.cursor.Cursor;
+import org.apache.ibatis.mapping.Environment;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.session.SqlSessionFactoryBuilder;
+import org.apache.ibatis.testcontainers.PgContainer;
+import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+
+@Tag("TestcontainersTests")
+class DirtySelectTest {
+
+ private static SqlSessionFactory sqlSessionFactory;
+
+ @BeforeAll
+ static void setUp() throws Exception {
+ Configuration configuration = new Configuration();
+ Environment environment = new Environment("development", new JdbcTransactionFactory(),
+ PgContainer.getUnpooledDataSource());
+ configuration.setEnvironment(environment);
+ configuration.addMapper(Mapper.class);
+ sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
+
+ BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),
+ "org/apache/ibatis/submitted/dirty_select/CreateDB.sql");
+ }
+
+ @Test
+ void shouldRollbackIfCalled() {
+ Integer id;
+ try (SqlSession sqlSession = sqlSessionFactory.openSession(false)) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ User user = mapper.insertReturn("Jimmy");
+ id = user.getId();
+ assertNotNull(id);
+ assertEquals("Jimmy", user.getName());
+ sqlSession.rollback();
+ }
+ try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ User user = mapper.selectById(id);
+ assertNull(user);
+ }
+ }
+
+ @Test
+ void shouldRollbackIfCalled_Xml() {
+ Integer id;
+ try (SqlSession sqlSession = sqlSessionFactory.openSession(false)) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ User user = mapper.insertReturnXml("Jimmy");
+ id = user.getId();
+ assertNotNull(id);
+ assertEquals("Jimmy", user.getName());
+ sqlSession.rollback();
+ }
+ try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ User user = mapper.selectById(id);
+ assertNull(user);
+ }
+ }
+
+ @Test
+ void shouldRollbackIfCalled_Provider() {
+ Integer id;
+ try (SqlSession sqlSession = sqlSessionFactory.openSession(false)) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ User user = mapper.insertReturnProvider("Jimmy");
+ id = user.getId();
+ assertNotNull(id);
+ assertEquals("Jimmy", user.getName());
+ sqlSession.rollback();
+ }
+ try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ User user = mapper.selectById(id);
+ assertNull(user);
+ }
+ }
+
+ @Test
+ void shouldRollbackIfCalled_Cursor() throws Exception {
+ Integer id;
+ try (SqlSession sqlSession = sqlSessionFactory.openSession(false)) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ try (Cursor cursor = mapper.insertReturnCursor("Kate")) {
+ Iterator iterator = cursor.iterator();
+ User user = iterator.next();
+ id = user.getId();
+ assertNotNull(id);
+ assertEquals("Kate", user.getName());
+ }
+ sqlSession.rollback();
+ }
+ try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ User user = mapper.selectById(id);
+ assertNull(user);
+ }
+ }
+
+ @Test
+ void shouldNonDirtySelectNotUnsetDirtyFlag() {
+ Integer id;
+ try (SqlSession sqlSession = sqlSessionFactory.openSession(false)) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ // INSERT
+ User user = new User();
+ user.setName("Bobby");
+ mapper.insert(user);
+ id = user.getId();
+ assertNotNull(id);
+ assertEquals("Bobby", user.getName());
+ // Non-dirty SELECT
+ mapper.selectById(id);
+ sqlSession.rollback();
+ }
+ try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ User user = mapper.selectById(id);
+ assertNull(user);
+ }
+ }
+
+ @Test
+ void shouldNonDirtySelectNotUnsetDirtyFlag_Cursor() throws Exception {
+ Integer id;
+ try (SqlSession sqlSession = sqlSessionFactory.openSession(false)) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ // INSERT
+ User user = new User();
+ user.setName("Bobby");
+ mapper.insert(user);
+ id = user.getId();
+ assertNotNull(id);
+ assertEquals("Bobby", user.getName());
+ // Non-dirty SELECT
+ try (Cursor cursor = mapper.selectCursorById(id)) {
+ Iterator iterator = cursor.iterator();
+ iterator.next();
+ }
+ sqlSession.rollback();
+ }
+ try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
+ Mapper mapper = sqlSession.getMapper(Mapper.class);
+ User user = mapper.selectById(id);
+ assertNull(user);
+ }
+ }
+
+}
diff --git a/src/test/java/org/apache/ibatis/submitted/dirty_select/Mapper.java b/src/test/java/org/apache/ibatis/submitted/dirty_select/Mapper.java
new file mode 100644
index 00000000000..65fc52fe40f
--- /dev/null
+++ b/src/test/java/org/apache/ibatis/submitted/dirty_select/Mapper.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2009-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ibatis.submitted.dirty_select;
+
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Options;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.apache.ibatis.cursor.Cursor;
+
+public interface Mapper {
+
+ @Select("select * from users where id = #{id}")
+ User selectById(Integer id);
+
+ @Select("select * from users where id = #{id}")
+ Cursor selectCursorById(Integer id);
+
+ @Select(value = "insert into users (name) values (#{name}) returning id, name", affectData = true)
+ User insertReturn(String name);
+
+ @Select(value = "insert into users (name) values (#{name}) returning id, name", affectData = true)
+ Cursor insertReturnCursor(String name);
+
+ User insertReturnXml(String name);
+
+ @SelectProvider(type = MyProvider.class, method = "getSql", affectData = true)
+ User insertReturnProvider(String name);
+
+ @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
+ @Insert("insert into users (name) values (#{name}) returning id, name")
+ int insert(User user);
+
+ static class MyProvider {
+ public static String getSql() {
+ return "insert into users (name) values (#{name}) returning id, name";
+ }
+ }
+}
diff --git a/src/test/java/org/apache/ibatis/submitted/dirty_select/User.java b/src/test/java/org/apache/ibatis/submitted/dirty_select/User.java
new file mode 100644
index 00000000000..eaec6746f64
--- /dev/null
+++ b/src/test/java/org/apache/ibatis/submitted/dirty_select/User.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2009-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ibatis.submitted.dirty_select;
+
+public class User {
+
+ private Integer id;
+ private String name;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/test/resources/org/apache/ibatis/submitted/dirty_select/CreateDB.sql b/src/test/resources/org/apache/ibatis/submitted/dirty_select/CreateDB.sql
new file mode 100644
index 00000000000..fe7d925cce5
--- /dev/null
+++ b/src/test/resources/org/apache/ibatis/submitted/dirty_select/CreateDB.sql
@@ -0,0 +1,22 @@
+--
+-- Copyright 2009-2022 the original author or authors.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+drop table if exists users;
+
+create table users (
+ id serial primary key,
+ name varchar(30)
+);
diff --git a/src/test/resources/org/apache/ibatis/submitted/dirty_select/Mapper.xml b/src/test/resources/org/apache/ibatis/submitted/dirty_select/Mapper.xml
new file mode 100644
index 00000000000..b6b69ebfc99
--- /dev/null
+++ b/src/test/resources/org/apache/ibatis/submitted/dirty_select/Mapper.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+