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;
}
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!
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
flushCachefrombooleantoenum.The
enumis defined as follows and the default value isDEFAULT.This could be a backward incompatible change if you explicitly specified
flushCachein@Optionsin an existing app.If anyone think of a better fix, please add a comment.