Mybatis-3: Need explicitly configure flushCache manully once using the Options annotation

Created on 9 May 2015  ·  3Comments  ·  Source: mybatis/mybatis-3

The default behavior of Insert annotation will flush 2nd cache.

@Insert("insert into person (id, firstname, lastname) values (#{id}, #{firstname}, #{lastname})")
public void create(Person person);

But after add something like, it didn't work

// file org.apache.ibatis.submitted.cache.PersonMapper
@Insert("insert into person (id, firstname, lastname) values (#{id}, #{firstname}, #{lastname})")
@Options(useGeneratedKeys = true, keyProperty="id")
public void create(Person person);

test case is below

  /*
   * 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 6 returns 3 row.
   *   But actual is 2, case fail, cache didn't flush!
   *   If didn't use Options it works though
   */
  @Test
  public void testplan4WithOptions() {
    try( SqlSession sqlSession1 = sqlSessionFactory.openSession(true)) {
      PersonMapper pm = sqlSession1.getMapper(PersonMapper.class);
      Assert.assertEquals(2, pm.findAll().size());
    }

    try ( SqlSession sqlSession2 = sqlSessionFactory.openSession(true)) {
      PersonMapper pm = sqlSession2.getMapper(PersonMapper.class);
      Person p = new Person(3, "hello", "world");
      pm.create(p);
    }

    try ( SqlSession sqlSession3 = sqlSessionFactory.openSession(true)) {
      PersonMapper pm = sqlSession3.getMapper(PersonMapper.class);
      Assert.assertEquals(3, pm.findAll().size());
    }
  }

I think it's because the default value of flushCache in Options is false which causing this problem,

public @interface Options {
    boolean flushCache() default false;
    // omit other....
}

Wouldn't it be better if flushCache is separate in Select, Insert, Update, Delete, like this, similar to the
xml config

public @interface Select {
    boolean useCache() default true;

    boolean flushCache() default false;
}

public @interface Insert {
    boolean flushCache() default true;
}

public @interface Update {
    boolean flushCache() default true;
}

public @interface Delete {
    boolean flushCache() default true;
}
bug

Most helpful comment

Thank you for the report!
Reading the source code, I think it should work as you expect.

I have fixed it by changing the type of flushCache from boolean to enum.
The enum is defined as follows and the default value is DEFAULT.

  public enum FlushCachePolicy {
    /** Works as 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
  }

This could be a backward incompatible change if you explicitly specified flushCache in @Options in an existing app.
If anyone think of a better fix, please add a comment.

All 3 comments

Thank you for the report!
Reading the source code, I think it should work as you expect.

I have fixed it by changing the type of flushCache from boolean to enum.
The enum is defined as follows and the default value is DEFAULT.

  public enum FlushCachePolicy {
    /** Works as 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
  }

This could be a backward incompatible change if you explicitly specified flushCache in @Options in an existing app.
If anyone think of a better fix, please add a comment.

Hi @harawata, this is just to tell you that I read the issue and I am Ok with the solution you proposed.

It will break existing code but we must fix it somehow.

Thanks for reviewing, Eduardo!

Was this page helpful?
0 / 5 - 0 ratings