繁体   English   中英

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

[英]MyBatis: how to bypass a local cache and directly hit the DB on specific select

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

用例1 :'从双重选择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);
}

我偶尔会在服务器上收到MyException错误,但无法在我的本地计算机上重现。 在所有情况下,对象始终在DB中。 所以我猜错误取决于第一次存储的对象是否在MyBatis本地缓存中,等待5分钟没有帮助,因为它从不检查实际的数据库。

所以我的问题是如何在不退回普通JDBC的情况下解决MyBatis中的上述用例?
能够以某种方式告知MyBatis不在特定调用中使用缓存值(最好)或在特定查询的所有调用中将是首选选项,但我也会考虑任何解决方法。

我不知道绕过本地缓存的方法,但有两种选择如何实现您的需要。

第一个选项是在select上设置flushCache="true" 这将在语句执行后清除缓存,以便下一个查询将命中数据库。

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

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

让我总结一下。
上一个答案的解决方案,查询中的' flushCache =“true” '选项,可以解决这两个用例。 它将在每次这样的'select'之后刷新缓存,因此下一个'select'语句将命中DB。 虽然执行'select'语句它可以正常工作,但是没关系,因为在第一个'select'之前缓存是空的。

另一种解决方案是开始一个新的会话。 我使用Spring,所以用@Transactional标记一个方法就足够了(propagation = Propagation.REQUIRES_NEW) 由于MyBatis会话与Spring事务相关联,因此每次调用该方法时都会导致创建另一个带有新缓存的MyBatis会话。

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

可以使用以下Options注释:

@Options(useCache=false, flushCache=FlushCachePolicy.TRUE)

除了罗曼和亚历山大的答案之外,还有一个解决方案:

 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(); 
                } 
            } 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM