某些查询不应该一直访问数据库。 例如,当您查询主数据 (例如系统设置,语言,翻译等)时,您可能希望避免一直通过网络发送相同的愚蠢查询(和结果)。 例如:

SELECT * FROM languages

大多数数据库都维护缓冲区高速缓存以加快这些查询的速度,因此您不必总是打磁盘。 一些数据库为每个游标维护结果集缓存,或者它们的JDBC驱动程序甚至可能直接在驱动程序中实现结果集缓存-例如,Oracle中的一项鲜为人知的功能 :

SELECT /*+ RESULT_CACHE */ * FROM languages

但是您可能没有使用Oracle, 并且由于修补JDBC很麻烦 ,因此您可能不得不在数据访问或服务层上一层或两层实施高速缓存:

class LanguageService {private Cache cache;List<Language> getLanguages() {List<Language> result = cache.get();if (result == null) {result = doGetLanguages();cache.put(result);}return result;}
}

而是在JDBC层中进行

尽管这在每个服务和方法级别上都可以正常工作,但是当您仅查询那些结果的一部分时,它可能很快就会变得乏味。 例如,当您添加其他过滤器时会怎样? 您是否也应该缓存该查询? 您应该在缓存上执行过滤器,还是每个过滤器至少访问数据库一次?

class LanguageService {private Cache cache;List<Language> getLanguages() { ... }List<Language> getLanguages(Country country) {// Another cache?// Query the cache only and delegate to//     getLanguages()?// Or don't cache this at all?}
}

如果我们有以下形式的缓存,那会不会很好:

Map<String, ResultSet> cache;

…缓存可重复使用的JDBC ResultSets (或更优:jOOQ Results ),并在每次遇到相同的查询字符串时返回相同的结果。

为此使用jOOQ的MockDataProvider

jOOQ附带了一个MockConnection ,它为您实现了JDBC Connection API, MockConnection了所有其他对象,例如PreparedStatementResultSet等。我们已经在上一篇博客文章中介绍了此有用的工具,用于单元测试 。

但是您也可以“模拟”您的连接以实现缓存! 考虑以下非常简单的MockDataProvider

class ResultCache implements MockDataProvider {final Map<String, Result<?>> cache = new ConcurrentHashMap<>();final Connection connection;ResultCache(Connection connection) {this.connection = connection;}@Overridepublic MockResult[] execute(MockExecuteContext ctx)throws SQLException {Result<?> result;// Add more sophisticated caching criteriaif (ctx.sql().contains("from language")) {// We're using this very useful new Java 8// API for atomic cache value calculationresult = cache.computeIfAbsent(ctx.sql(),sql -> DSL.using(connection).fetch(ctx.sql(),ctx.bindings()));}// All other queries go to the databaseelse {result = DSL.using(connection).fetch(ctx.sql(), ctx.bindings());}return new MockResult[] { new MockResult(result.size(), result)};}
}

显然,这是一个非常简单的示例。 真正的缓存将涉及无效性(基于时间,基于更新等)以及更多的选择性缓存条件,而不仅仅是from language匹配。

但是事实是,使用上述ResultCache ,我们现在可以包装所有JDBC连接,并防止对从语言表中查询的所有查询多次访问数据库! 使用jOOQ API的示例:

DSLContext normal = DSL.using(connection);
DSLContext cached = DSL.using(new MockConnection(new ResultCache(connection))
);// This executs a select count(*) from language query
assertEquals(4, cached.fetchCount(LANGUAGE));
assertEquals(4, normal.fetchCount(LANGUAGE));// Let's add another language (using normal config):
LanguageRecord lang = normal.newRecord(LANGUAGE);
lang.setName("German");
lang.store();// Checking again on the language table:
assertEquals(4, cached.fetchCount(LANGUAGE));
assertEquals(5, normal.fetchCount(LANGUAGE));

缓存就像一个魅力! 请注意,当前的缓存实现仅基于SQL字符串(应该如此)。 如果仅对SQL字符串进行少量修改,就会遇到另一个高速缓存未命中的情况,查询将返回数据库:

// This query is not the same as the cached one, it
// fetches two count(*) expressions. Thus we go back
// to the database and get the latest result.
assertEquals(5, (int) cached.select(count(),count()).from(LANGUAGE).fetchOne().value1());// This still has the "stale" previous result
assertEquals(4, cached.fetchCount(LANGUAGE));

结论

缓存很难。 很难。 除了并发,命名和一处错误外,它还是软件中最困难的三个问题之一。

本文不建议在JDBC级别实现缓存。 您可能会自己决定,也可能不会。 但是,当您这样做时,就可以看到使用jOOQ实现这种缓存有多么容易。

最好的是,您不必在所有应用程序中都使用jOOQ。 您可以将其仅用于此特定用例(以及用于模拟JDBC ),并继续使用JDBC,MyBatis,Hibernate等,只要使用jOOQ MockConnection修补其他框架的JDBC连接即可。

翻译自: https://www.javacodegeeks.com/2015/03/hack-up-a-simple-jdbc-resultset-cache-using-jooqs-mockdataprovider.html

使用jOOQ的MockDataProvider破解简单的JDBC ResultSet缓存相关推荐

  1. junit链接mysql_java – 使用JUnit进行简单的JDBC连接测试

    我想简单测试JDBC连接,我不使用框架,只使用JDBC和JUnit.我可以用JUnit执行此测试吗?我不知道如何测试加载驱动程序,请给我一些连接测试的例子. 连接客户端: package newpac ...

  2. 1138:破解简单密码

    1138:破解简单密码 Description 密码是我们生活中非常重要的东西,我们的那么一点不能说的秘密就全靠它了.哇哈哈. 接下来原子要在密码上再加一套密码,虽然简单但也安全. 假设老王原来一个B ...

  3. 如何使用Java 8 FlatMap JDBC ResultSet?

    您还不喜欢机能吗? 这样标题可能不会引起您的共鸣-但文章会! 相信我. 本质上,我们想要这样: +------+------+------+ | col1 | col2 | col3 | +----- ...

  4. 从JDBC ResultSet创建对象流

    Java 8中引入了Stream API和Lambda功能 ,使我们能够从JDBC ResultSet优雅地转换为仅提供映射功能的对象流. 这种功能当然可以是lambda. 基本上,这个想法是使用Re ...

  5. php 高效缓存类,简单高效的文件缓存php类

    简单高效的文件缓存php类 class FileCache { public $keyPrefix = ''; public $cachePath = ''; public $cacheFileSuf ...

  6. 由DB2分页想到的,关于JDBC ResultSet 处理大数据量

    最近在处理DB2 ,查询中,发现如下问题.如果一个查询 count(*),有几十万行,分页如何实现 select row_number() over (order by fid desc ) as r ...

  7. hibernate二级缓存(三) 自定义实现一个简单的hibernate二级缓存

    hibernate二级缓存(三) 自定义实现一个简单的hibernate二级缓存 前面我们已经提及过hibernate内部为二级缓存的扩展做了很多的实现.我们只需要实现RegionFactoryTem ...

  8. Oracle 12c 简单的jdbc使用

    2019独角兽企业重金招聘Python工程师标准>>> 转账请注明出处:http://blog.csdn.net/anxpp/article/details/51345252,谢谢! ...

  9. 一个简单的JDBC通用工具

    支持多种数据库,统一方式产生连接,最优化.最简单方式释放资源. 欢迎拍砖! import org.apache.commons.logging.Log;  import org.apache.comm ...

最新文章

  1. python文件读取方法read(size)的含义是_Python基于read(size)方法读取超大文件
  2. iframe父页面获取iframe子页面的元素 与 iframe子页面获取父页面元素
  3. 如何快速切换静态和动态ip
  4. Android Studio的下载和安装教程(从ADT到AS)
  5. react-native run-android的输出
  6. Elastic-job使用及原理
  7. 最好的Linux C/C++ IDE Windows ALL IDE,第一效率,第零浪漫
  8. java switch小程序,微信小程序 switch组件详解及简单实例
  9. office是python打开方式_Python读取word文本操作详解
  10. 使用AForge录制视频
  11. linux蓝牙主从机模式代码,技术贴 丨 Android 蓝牙BLE开发Docker入门与WMS2.0实例
  12. Mybatis-Plus入门案例、以及为什么不建议使用MP?
  13. QQ聊天机器人 Delphi代码
  14. 论文写作 之 Introduction
  15. 基于canvas+uniapp的9宫格拼图游戏组件
  16. STORJ 有实际应用
  17. ipad适用计算机专业么,并不适合所有人 iPad Pro买前需认识这几点
  18. MVG读书笔记——几何变换续
  19. 在springboot整合mybatis遇到的数据库连接不上问题解决
  20. requireJS 加载css、less文件

热门文章

  1. ssm(Spring+Spring mvc+mybatis)Spring配置文件——applicationContext-servlet.xml
  2. 人脸检测源码facedetection
  3. 使用ueditor实现多图片上传案例——DaoImpl层(ShoppingDaoImpl)
  4. MyBatis中多表查询(N+1方式)
  5. 2018蓝桥杯省赛---java---C---9(小朋友崇拜圈)
  6. 开发环境 Minio 添加桶的操作流程-页面操作
  7. php类常量的特点,php类常量是什么?类常量用法详解
  8. 微型计算机中被处理信息称为,2011海南省计算机等级考试试题 二级C试题考资料...
  9. URLConnection-URL连接
  10. Spring4.2.6+SpringMVC4.2.6+MyBatis3.4.0 整合