Java MyBatis:如何绕过本地缓存并直接命中特定选择上的数据库

Java MyBatis:如何绕过本地缓存并直接命中特定选择上的数据库,java,spring,mybatis,Java,Spring,Mybatis,我使用MyBatis 3.1 当我需要绕过MyBatis本地缓存并直接访问数据库时,我有两个用例 因为MyBatis配置文件只有全局设置,所以它不适用于我的情况,因为我需要它作为例外,而不是默认设置。MyBatisXML语句的属性似乎不包含此选项 用例1:“从dual中选择sysdate” MyBatis缓存使该缓存在MyBatis会话中始终返回相同的值。当我试图复制过时条目的情况时,这会在集成测试中导致问题 我的解决方法只是使用一个普通的JDBC调用 用例2:“从一个线程中选择”并不总是看到由

我使用MyBatis 3.1
当我需要绕过MyBatis本地缓存并直接访问数据库时,我有两个用例
因为MyBatis配置文件只有全局设置,所以它不适用于我的情况,因为我需要它作为例外,而不是默认设置。MyBatisXML语句的属性似乎不包含此选项

用例1:“从dual中选择sysdate”
MyBatis缓存使该缓存在MyBatis会话中始终返回相同的值。当我试图复制过时条目的情况时,这会在集成测试中导致问题
我的解决方法只是使用一个普通的JDBC调用

用例2:“从一个线程中选择”并不总是看到由另一个线程写入的值
线程1:

SomeObject stored = dao.insertSomeObject(obj);
runInAnotherThread(stored.getId());
//complete and commit
线程2:

//'id' received as an argument provided to 'runInAnotherThread(...)'
SomeObject stored = dao.findById(id);
int count = 0;
while(stored == null && count < 300) {
    ++count;
    Thread.sleep(1000);
    stored = dao.findById(id);
}
if (stored == null) {
    throw new MyException("There is no SomeObject with id="+id);
}
//'id'作为提供给'runInOtherThread(…)'的参数接收
someobjectstored=dao.findById(id);
整数计数=0;
while(存储==null&&count<300){
++计数;
睡眠(1000);
存储=dao.findById(id);
}
if(存储==null){
抛出新的MyException(“没有id为=“+id”的SomeObject);
}
我偶尔会在服务器上收到MyException错误,但无法在本地计算机上重现。在所有情况下,对象始终位于数据库中。因此,我猜错误取决于第一次存储的对象是否在MyBatis本地缓存中,等待5分钟没有帮助,因为它从不检查实际的数据库

因此,我的问题是如何在MyBatis中解决上述用例,而不回到普通的JDBC

在某种特定的调用中(最好的)或在对特定查询的所有调用中都可以使用MybATIs来指定MybATIs不是首选的选项,但是我也会考虑任何解决方案。

< P>我不知道绕过本地缓存的方法,但是有两种选项来实现您所需要的。p> 第一个选项是在
选择上设置
flushCache=“true”
。这将在语句执行后清除缓存,以便下一个查询将命中数据库

    <select id="getCurrentDate" resultType="date" flushCache="true">
        SELECT SYSDATE FROM DUAL
    </select>  

从DUAL中选择SYSDATE
另一种选择是使用语句级本地缓存。默认情况下,在会话期间使用本地缓存(通常转换为事务)。这由
localCacheScope
选项指定,并根据会话工厂进行设置。因此,这将影响使用此mybatis会话工厂的所有查询。

让我总结一下
来自上一个答案的解决方案,查询上的“flushCache=“true””选项,可以工作并解决这两个用例。它将在每次这样的“选择”之后刷新缓存,因此下一个“选择”语句将命中数据库。虽然它在执行“select”语句后起作用,但由于缓存在第一个“select”之前是空的,所以它是正常的

另一个解决方案是启动新会话。我使用Spring,所以用@Transactional(propagation=propagation.REQUIRES_NEW)标记方法就足够了。由于MyBatis会话绑定到Spring事务,这将导致在每次调用该方法时使用新缓存创建另一个MyBatis会话


出于某种原因,查询中的MyBatis选项“useCache=“false”不起作用。

除了Roman和Alexander的答案外,还有一个解决方案:

 Configuration configuration = MyBatisUtil.getSqlSessionFactory().getConfiguration(); 
            Collection<Cache> caches = configuration.getCaches(); 

           //If you have multiple caches and want a particular to get deleted.           
          // Cache cache = configuration.getCache("PPL"); // namespace of particular XML
            for (Cache cache : caches) { 
                Lock w = cache.getReadWriteLock().writeLock(); 
                w.lock(); 
                try { 
                    cache.clear(); 
                } finally { 
                    w.unlock(); 
                } 
            } 
Configuration-Configuration=MyBatisUtil.getSqlSessionFactory().getConfiguration();
Collection caches=configuration.getCaches();
//如果您有多个缓存,并且希望删除特定的缓存。
//Cache Cache=configuration.getCache(“PPL”);//特定XML的名称空间
对于(缓存:缓存){
锁w=cache.getReadWriteLock().writeLock();
w、 锁();
试试{
cache.clear();
}最后{
w、 解锁();
} 
} 
可以使用以下注释:

@Options(useCache=false, flushCache=FlushCachePolicy.TRUE)
“flushCache=“true”确实有效,谢谢,值得称赞。第二种选择,正如你刚才注意到的,是一种全球性的选择,所以我会避免它。