diff --git a/src/main/java/org/apache/ibatis/annotations/Options.java b/src/main/java/org/apache/ibatis/annotations/Options.java index 671fa194706..fe7589ea367 100644 --- a/src/main/java/org/apache/ibatis/annotations/Options.java +++ b/src/main/java/org/apache/ibatis/annotations/Options.java @@ -29,9 +29,22 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Options { + /** + * The options for the {@link Options#flushCache()}. + * The default is {@link FlushCachePolicy#DEFAULT} + */ + public enum FlushCachePolicy { + /** false for select statement; true for insert/update/delete statement. */ + DEFAULT, + /** Flushes cache regardless of the statement type. */ + TRUE, + /** Does not flush cache regardless of the statement type. */ + FALSE + } + boolean useCache() default true; - boolean flushCache() default false; + FlushCachePolicy flushCache() default FlushCachePolicy.DEFAULT; ResultSetType resultSetType() default ResultSetType.FORWARD_ONLY; diff --git a/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java b/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java index 9b4e1c27f9e..440a81274a8 100644 --- a/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java +++ b/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java @@ -55,6 +55,7 @@ import org.apache.ibatis.annotations.TypeDiscriminator; import org.apache.ibatis.annotations.Update; import org.apache.ibatis.annotations.UpdateProvider; +import org.apache.ibatis.annotations.Options.FlushCachePolicy; import org.apache.ibatis.binding.BindingException; import org.apache.ibatis.binding.MapperMethod.ParamMap; import org.apache.ibatis.builder.BuilderException; @@ -292,7 +293,11 @@ void parseStatement(Method method) { } if (options != null) { - flushCache = options.flushCache(); + if (FlushCachePolicy.TRUE.equals(options.flushCache())) { + flushCache = true; + } else if (FlushCachePolicy.FALSE.equals(options.flushCache())) { + flushCache = false; + } useCache = options.useCache(); fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348 timeout = options.timeout() > -1 ? options.timeout() : null; diff --git a/src/site/es/xdoc/java-api.xml b/src/site/es/xdoc/java-api.xml index 073e913f633..c003c884ab9 100644 --- a/src/site/es/xdoc/java-api.xml +++ b/src/site/es/xdoc/java-api.xml @@ -395,7 +395,7 @@ try (SqlSession session = sqlSessionFactory.openSession()) { @Options Method Attributes of mapped statements. - Esta anotación proporciona acceso a un gran conjunto de opciones de configuración que normalmente aparecen como atributos en los mapped statements. En lugar de complicar cada anotación existente la anotación Options proporciona una forma sencilla y concisa de acceder a estas opciones. Atributos: useCache=true, flushCache=false, resultSetType=FORWARD_ONLY, statementType=PREPARED, fetchSize=-1, timeout=-1, useGeneratedKeys=false, keyProperty=“id”, keyColumn=“”. Es importante comprender que las anotaciones en Java no permiten indicar un valor nulo. Por lo tanto, cuando usas la anotación Options el statement usará todos los valores por defecto. Presta atención a estos valores pro defecto para evitar comportamientos inesperados. La keyColumn solo se requiere para algunas bases de datos (como PostgreSQL) cuando la columna no es la primera columna de la tabla. + Esta anotación proporciona acceso a un gran conjunto de opciones de configuración que normalmente aparecen como atributos en los mapped statements. En lugar de complicar cada anotación existente la anotación Options proporciona una forma sencilla y concisa de acceder a estas opciones. Atributos: useCache=true, flushCache=FlushCachePolicy.DEFAULT, resultSetType=FORWARD_ONLY, statementType=PREPARED, fetchSize=-1, timeout=-1, useGeneratedKeys=false, keyProperty=“id”, keyColumn=“”. Es importante comprender que las anotaciones en Java no permiten indicar un valor nulo. Por lo tanto, cuando usas la anotación Options el statement usará todos los valores por defecto. Presta atención a estos valores pro defecto para evitar comportamientos inesperados. La keyColumn solo se requiere para algunas bases de datos (como PostgreSQL) cuando la columna no es la primera columna de la tabla. diff --git a/src/site/ja/xdoc/java-api.xml b/src/site/ja/xdoc/java-api.xml index 3bbc810b1d2..3348c10f2fc 100644 --- a/src/site/ja/xdoc/java-api.xml +++ b/src/site/ja/xdoc/java-api.xml @@ -409,7 +409,7 @@ try (SqlSession session = sqlSessionFactory.openSession()) { Method マップドステートメントの属性 このアノテーションを使うと、通常マップドステートメントの属性として指定される多様なスイッチや設定オプションにアクセスすることができます。Options アノテーションによって、各ステートメントのアノテーションを複雑化することなく、一貫したクリーンな方法で設定にアクセスできるよう工夫されています。キー: Attributes: - useCache=true, flushCache=false, resultSetType=FORWARD_ONLY, + useCache=true, flushCache=FlushCachePolicy.DEFAULT, resultSetType=FORWARD_ONLY, statementType=PREPARED, fetchSize=-1, timeout=-1, useGeneratedKeys=false, keyProperty="id", keyColumn="". Java アノテーションを使う場合、値として null を指定することはできないという制限があります。これはどういうことかというと、Options アノテーションを付加したステートメントにはデフォルトのオプションが適用されるということです。予期しない動作を防ぐため、各オプションのデフォルト値を把握しておくようにしてください。

diff --git a/src/site/ko/xdoc/java-api.xml b/src/site/ko/xdoc/java-api.xml index ca1605d89c3..0a32484b9de 100644 --- a/src/site/ko/xdoc/java-api.xml +++ b/src/site/ko/xdoc/java-api.xml @@ -513,7 +513,7 @@ try (SqlSession session = sqlSessionFactory.openSession()) { 이 애노테이션은 매핑된 구문에 속성으로 존재하는 많은 분기(switch)와 설정 옵션에 접근할 수 있다. 각 구문을 복잡하게 만들기 보다 Options 애노테이션으로 일관되고 깔끔한 방법으로 설정 할수 있게 한다. 사용가능한 속성들 : useCache=true, - flushCache=false, + flushCache=FlushCachePolicy.DEFAULT, resultSetType=FORWARD_ONLY, statementType=PREPARED, fetchSize=-1, diff --git a/src/site/xdoc/java-api.xml b/src/site/xdoc/java-api.xml index 13b3dd71b6a..e95a7822a49 100644 --- a/src/site/xdoc/java-api.xml +++ b/src/site/xdoc/java-api.xml @@ -430,7 +430,7 @@ try (SqlSession session = sqlSessionFactory.openSession()) { This annotation provides access to the wide range of switches and configuration options that are normally present on the mapped statement as attributes. Rather than complicate each statement annotation, the Options annotation provides a consistent and clear way to access these. Attributes: - useCache=true, flushCache=false, resultSetType=FORWARD_ONLY, + useCache=true, flushCache=FlushCachePolicy.DEFAULT, resultSetType=FORWARD_ONLY, statementType=PREPARED, fetchSize=-1, timeout=-1, useGeneratedKeys=false, keyProperty="id", keyColumn="". It's important to understand that with Java Annotations, there is no way to specify null as a value. diff --git a/src/site/zh/xdoc/java-api.xml b/src/site/zh/xdoc/java-api.xml index d76204a4592..150da96fe29 100644 --- a/src/site/zh/xdoc/java-api.xml +++ b/src/site/zh/xdoc/java-api.xml @@ -670,7 +670,7 @@ select,是映射语句(也就是映射器方 而不是将每条语句注解变复 杂,Options 注解提供连贯清晰的方式 来访问它们。属性:useCache=true , -flushCache=false +flushCache=FlushCachePolicy.DEFAULT , resultSetType=FORWARD_ONLY , statementType=PREPARED , diff --git a/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java b/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java index 361aaed7145..8c84a81233c 100644 --- a/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java +++ b/src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java @@ -168,4 +168,96 @@ public void testplan3() { } } + /*- + * Test case for #405 + * + * Test Plan with Autocommit on: + * 1) SqlSession 1 executes "select * from A". + * 2) SqlSession 1 closes. + * 3) SqlSession 2 executes "insert into person (id, firstname, lastname) values (3, hello, world)" + * 4) SqlSession 2 closes. + * 5) SqlSession 3 executes "select * from A". + * 6) SqlSession 3 closes. + * + * Assert: + * Step 5 returns 3 row. + */ + @Test + public void shouldInsertWithOptionsFlushesCache() { + SqlSession sqlSession1 = sqlSessionFactory.openSession(true); + try { + PersonMapper pm = sqlSession1.getMapper(PersonMapper.class); + Assert.assertEquals(2, pm.findAll().size()); + } finally { + sqlSession1.close(); + } + + SqlSession sqlSession2 = sqlSessionFactory.openSession(true); + try { + PersonMapper pm = sqlSession2.getMapper(PersonMapper.class); + Person p = new Person(3, "hello", "world"); + pm.createWithOptions(p); + } finally { + sqlSession2.close(); + } + + SqlSession sqlSession3 = sqlSessionFactory.openSession(true); + try { + PersonMapper pm = sqlSession3.getMapper(PersonMapper.class); + Assert.assertEquals(3, pm.findAll().size()); + } finally { + sqlSession3.close(); + } + } + + /*- + * Test Plan with Autocommit on: + * 1) SqlSession 1 executes select to cache result + * 2) SqlSession 1 closes. + * 3) SqlSession 2 executes insert without flushing cache + * 4) SqlSession 2 closes. + * 5) SqlSession 3 executes select (flushCache = false) + * 6) SqlSession 3 closes. + * 7) SqlSession 4 executes select (flushCache = true) + * 8) SqlSession 4 closes. + * + * Assert: + * Step 5 returns 2 row. + * Step 7 returns 3 row. + */ + @Test + public void shouldApplyFlushCacheOptions() { + SqlSession sqlSession1 = sqlSessionFactory.openSession(true); + try { + PersonMapper pm = sqlSession1.getMapper(PersonMapper.class); + Assert.assertEquals(2, pm.findAll().size()); + } finally { + sqlSession1.close(); + } + + SqlSession sqlSession2 = sqlSessionFactory.openSession(true); + try { + PersonMapper pm = sqlSession2.getMapper(PersonMapper.class); + Person p = new Person(3, "hello", "world"); + pm.createWithoutFlushCache(p); + } finally { + sqlSession2.close(); + } + + SqlSession sqlSession3 = sqlSessionFactory.openSession(true); + try { + PersonMapper pm = sqlSession3.getMapper(PersonMapper.class); + Assert.assertEquals(2, pm.findAll().size()); + } finally { + sqlSession3.close(); + } + + SqlSession sqlSession4 = sqlSessionFactory.openSession(true); + try { + PersonMapper pm = sqlSession4.getMapper(PersonMapper.class); + Assert.assertEquals(3, pm.findWithFlushCache().size()); + } finally { + sqlSession4.close(); + } + } } diff --git a/src/test/java/org/apache/ibatis/submitted/cache/PersonMapper.java b/src/test/java/org/apache/ibatis/submitted/cache/PersonMapper.java index 623f937be40..cbd71db723e 100644 --- a/src/test/java/org/apache/ibatis/submitted/cache/PersonMapper.java +++ b/src/test/java/org/apache/ibatis/submitted/cache/PersonMapper.java @@ -20,6 +20,8 @@ import org.apache.ibatis.annotations.CacheNamespace; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Options; +import org.apache.ibatis.annotations.Options.FlushCachePolicy; import org.apache.ibatis.annotations.Select; @CacheNamespace @@ -28,9 +30,21 @@ public interface PersonMapper { @Insert("insert into person (id, firstname, lastname) values (#{id}, #{firstname}, #{lastname})") public void create(Person person); + @Insert("insert into person (id, firstname, lastname) values (#{id}, #{firstname}, #{lastname})") + @Options + public void createWithOptions(Person person); + + @Insert("insert into person (id, firstname, lastname) values (#{id}, #{firstname}, #{lastname})") + @Options(flushCache = FlushCachePolicy.FALSE) + public void createWithoutFlushCache(Person person); + @Delete("delete from person where id = #{id}") public void delete(int id); @Select("select id, firstname, lastname from person") public List findAll(); + + @Select("select id, firstname, lastname from person") + @Options(flushCache = FlushCachePolicy.TRUE) + public List findWithFlushCache(); }