`

ibatis oscache配置以及【文件名、目录名或卷标语法不正确】错误解决

阅读更多

sqlmap-config.xml 配置如下: 

 <settings
      cacheModelsEnabled="true"
      enhancementEnabled="true"
      maxTransactions="20"
         maxRequests="32"
         maxSessions="20"
         errorTracingEnabled="true"
         useStatementNamespaces="true"
   />

 

User.xml配置:

<cacheModel id="userCache" type="OSCACHE">
  <flushInterval hours="24"/>
  <flushOnExecute statement="User.updateUser"/>
  <property name="size" value="1000" />
 </cacheModel>
 
 <resultMap id="UserResult" class="User">
 
  <result property="username" column="nodeName"/>
  
  <result property="address" column="hrefAddress"/>
 
 </resultMap>
 
 <select id="getUserbyUsername" resultMap="UserResult" cacheModel="userCache">
  select hrefAddress,nodeName from tree_table WHERE nodeName like '%$username$%'
 </select>
 
 <update id="updateUser" parameterClass="User">
  update
  tree_table
  set hrefAddress = #address#
  where nodeName = #username#
 </update>

 

 

 

oscache.properties配置如下:

# 是否使用内存作为缓存空间
cache.memory=true
cache.key=_oscache_cache
# 如果使用磁盘缓存(cache.memory=false),则需要指定磁盘存储接口实现
cache.persistence.class=com.opensymphony.oscache.plugins.diskpersistence.DiskPersistenceListener
# ie Windows:
cache.path=D:\\dcache
# 缓存调度算法
cache.algorithm=com.opensymphony.oscache.base.algorithm.LRUCache
# 内存中缓存的最大容量
cache.capacity=1000

 

运行报错:

com.opensymphony.oscache.base.persistence.CachePersistenceException: Unable to write 'D:\dcache\application\1184404535|1614558766.cache' in the cache. Exception: java.io.FileNotFoundException, Message: D:\dcache\application\1184404535|1614558766.cache (文件名、目录名或卷标语法不正确。)
 at com.opensymphony.oscache.plugins.diskpersistence.AbstractDiskPersistenceListener.store(AbstractDiskPersistenceListener.java:376)
 at com.opensymphony.oscache.plugins.diskpersistence.AbstractDiskPersistenceListener.store(AbstractDiskPersistenceListener.java:238)
 at com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache.persistStore(AbstractConcurrentReadCache.java:1113)
 at com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache.put(AbstractConcurrentReadCache.java:1616)
 at com.opensymphony.oscache.base.algorithm.AbstractConcurrentReadCache.put(AbstractConcurrentReadCache.java:863)
 at com.opensymphony.oscache.base.Cache.putInCache(Cache.java:624)
 at com.opensymphony.oscache.base.Cache.putInCache(Cache.java:601)
 at com.opensymphony.oscache.general.GeneralCacheAdministrator.putInCache(GeneralCacheAdministrator.java:270)
 at com.ibatis.sqlmap.engine.cache.oscache.OSCacheController.putObject(OSCacheController.java:70)
 at com.ibatis.sqlmap.engine.cache.CacheModel.putObject(CacheModel.java:318)
 at com.ibatis.sqlmap.engine.mapping.statement.CachingStatement.executeQueryForObject(CachingStatement.java:80)
 at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:565)
 at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:540)
 at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForObject(SqlMapSessionImpl.java:106)
 at com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.queryForObject(SqlMapClientImpl.java:84)
 at net.chinaideal.samples.ibatis.dao.UserDAOImpl.getUserByUsername(UserDAOImpl.java:36)
 at net.chinaideal.samples.ibatis.test.TestDAO1.main(TestDAO1.java:63)

 

问题出在Ibatis生成OScache缓存文件时,命名规则与Windows 文件系统冲突(因为在Windows中,文件名不能包含下面任何字符: \ / : * ? " < > |或文件名不能过长)。

找到问题后就可以开始对症下药了:
从文件名“D:\dcache\application\1184404535|1614558766.cache ",可以看出,缓存文件名是按照查询语句参数等生成的。
于是找到生成文件名的类:iBatis 的 com.ibatis.sqlmap.engine.cache.CacheKey,它的 toString() 方法返回值就是文件名:

public String toString() {
  StringBuffer returnValue = new StringBuffer().append(hashcode).append('|').append(checksum);
  for (int i=0; i < paramList.size(); i++) {
    returnValue.append('|').append(paramList.get(i));
  }
  return returnValue.toString();
}
上面代码生成的文件名就可能包含竖线符号("|"),这在 Windows 平台是不允许的,在 Linux 下是不受此约束的。为了能让 iBatis 在使用文件缓存时保持平台独立性, 在该 toString() 方法最后返回时把 | 换成都能够接受的符号,比如 -,即把 return 语句改为:
return returnValue.toString().replace('|', '-');
可以把修正编译好的 CacheKey.class 替换掉 iBatis jar 包中的相应位置的 CacheKey.class。

问题解决了,但还是得注意几点:
1. 即使是使用其它缓存实现,也都是由这个 CacheKey 来生成 Key 的,所以若有可能使用其它缓存组件,缓存文件时同样有可能出现类似的问题。
2. 如果 CacheKey 在结合 SQL 和 参数生成的文件名过长可能也会是个问题,受限于不同的文件系统。设置的缓存目录不要过深,适时完全自定 toString() 方法。
3. 还有,关于是从缓存中取数据还是从数据库取得问题,这个 CacheKey 的 equals() 方法值得细究

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics