mybatis一级缓存导致同一事务中生成oracle序列重复问题


一级缓存背景知识

Mybatis的一级缓存是指Session缓存。一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。
也就是在同一个SqlSession中,执行相同的查询SQL,第一次会去数据库进行查询,并写到缓存中;

问题回放

问题代码:

@Transactional(rollbackFor = { Exception.class })
public boolean generatorIds() throws Exception {
   …
   List<String> ids = Lists.newArrayList();
     for (int i = 0; i < users.size(); ++i) {
      ids.add(xxMapper.generateNextId());
   }
    System.out.println(ids);
   …
}

Mybatis 问题sql (generateNextId):

select lpad(seq_document_id.nextval, 12, 0) from db_instance_config

预期结果:

生成不重复的sequenceid集合

实际结果:

重复的sequenceid集合

解决方案一(已验证):让同一sqlsession中sql动态变化

where条件变化等值条件

改造代码

@Transactional(rollbackFor = { Exception.class })
public boolean generatorIds() throws Exception {
   …
   List<String> ids = Lists.newArrayList();
     for (int i = 0; i < users.size(); ++i) {
      ids.add(xxMapper.generateNextId(i));
   }
     System.out.println(ids);
   …
}

改造sql

select lpad(seq_document_id.nextval, 12, 0) from db_instance_config where #{i} = #{i}

解决方案二(未验证):修改一级缓存范围

一级缓存的范围有SESSION和STATEMENT两种,默认是SESSION,如果不想使用一级缓存,可以把一级缓存的范围指定为STATEMENT,这样每次执行完一个Mapper中的语句后都会将一级缓存清除。
如果需要更改一级缓存的范围,可以在Mybatis的配置文件中,在下通过localCacheScope指定。

<setting name="localCacheScope" value="STATEMENT"/>

发表评论

0 评论
  • 最新评论
  • 按热度排序