功能描述: 先从缓存获取数据,如果缓存没有,就从数据库获取数据,并设置到缓存中,返回数据。

        如果数据库中没有数据,需要设置一个缓存标记flagKey,防止暴击访问数据库,用缓存保护数据库。

        当删除缓存key时,需要同时删除flagKey,保证数据库可被访问。

  关于java泛型的知识点,这里就跳过了。不理解的就自己去百度一下。

  直接上代码:

1.先定义泛型接口,用于写从数据库获取数据的方法。

/**
* 普通数据获取器
*
*/
public interface DataGeter<T> { /**
* 获取数据接口
* @return
*/
public T getData();
}

2.工具类。有一些方法需要自己写,看注释。

public class DataUtil {

    /**json转换工具*/
private static Gson gson = new Gson(); /**一天的过期秒数*/
private static final int ONE_DAY_EXPIRE_SECONDS = 1 * 24 * 60 * 60; /**
* 获取redis中获取指定data,如果redis中不存在,则从DataGeter接口中获取,并且写入redis<br/>
* 注:该方法会自动创建一个cacheKey + "_flag"的缓存key,作为标记flagKey
* @param cacheKey-缓存key
* @param clazz-获取目标类型
* @param dataGeter-数据获取器,原始数据源
* @param expireSeconds-缓存失效时间
* @return
*/
public static <T> T getDataFromRedisOrDataGeter(String cacheKey, Class<T> clazz, DataGeter<T> dataGeter,int expireSeconds) { T val = RedisClient.getValue(cacheKey, clazz);
if (val != null) {
//让热数据一直热下去 <单个key/value>,设置缓存有效期。
haveChanceToSetKeyExpireTime( cacheKey, expireSeconds) ;
return val;
}
if (RedisClient.existsKey(RedisClient.getFlagKey(cacheKey))) {
return null;
} try {
        //本地锁
Object lockObject = LockObjectUtil.getLockObject(cacheKey);
synchronized (lockObject) {// 为提升性能 这里不使用分布式锁
// 标记key,防止集合为空时还不停从数据库中读取数据
T data = null;
try {
data = dataGeter.getData();
} catch (DBException e) {
e.printStackTrace();
throw e;
}
if (data != null) {
// 这里最后才设置flag,以免分布式环境下dataGeter.getData();获取慢,导致后续请求从缓存中取不到数据
//有值不设置flag
RedisClient.setValue(cacheKey, data, expireSeconds <= 0 ? RedisDataSource.DEFAULT_EXPIRE_SECONDS : expireSeconds, false);
} else {
// 不存在数据则往缓存中插入一个flag,过期时间为一天
RedisClient.setValue(RedisClient.getFlagKey(cacheKey), true, ONE_DAY_EXPIRE_SECONDS);
}
return data;
}
} finally {
//释放锁
LockObjectUtil.disposeLock(cacheKey);
} } }

当调用工具类的方法时,写匿名内部类,去实现从数据库获取数据的逻辑。

用泛型写Redis缓存与数据库操作工具类的更多相关文章

  1. Java SE 之 数据库操作工具类(DBUtil)设计

    JDBC创建数据库基本连接 //1.加载驱动程序 Class.forName(driveName); //2.获得数据库连接 Connection connection = DriverManager ...

  2. Redis缓存和数据库一致性问题

    工作中,经常会遇到缓存和数据库数据一致性问题.从理论上设置过期时间,是保证最终一致性的解决方案.这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可 ...

  3. 本地缓存,Redis缓存,数据库DB查询(结合代码分析)

    问题背景 为什么要使用缓存?本地缓存/Redis缓存/数据库查询优先级? 一.为什么要使用缓存 原因:CPU的速度远远高于磁盘IO的速度问题:很多信息存在数据库当中的,每次查询数据库就是一次IO操作所 ...

  4. 注解与AOP切面编程实现redis缓存与数据库查询的解耦

    一般缓存与数据库的配合使用是这样的. 1.查询缓存中是否有数据. 2.缓存中无数据,查询数据库. 3.把数据库数据插入到缓存中. 其实我们发现 1,3 都是固定的套路,只有2 是真正的业务代码.我们可 ...

  5. Redis缓存与数据库一致性解决方案

    背景 缓存是数据库的副本,应用在查询数据时,先从缓存中查询,如果命中直接返回,如果未命中,去数据库查询最新数据并返回,同时写入缓存. 缓存能够有效地加速应用的读写速度,同时也可以降低后端负载.是应用架 ...

  6. 结合场景使用Redis缓存与数据库同步

    Redis缓存与MySQL数据库与同步 什么场景用到了Redis缓存? 1.广告数据 2.搜索时,分类品牌名称,分类名称和规格数据 3.购物车 4.支付 问题:如何实现? 1.广告数据 先查询Redi ...

  7. JAVA 数据库操作工具类----sqllite

    package com.asc.db; import android.content.ContentValues; import android.content.Context; import and ...

  8. JavaWeb网上图书商城完整项目-数据库操作工具类2-MapHandle的高级用法

    1.现在在上面一章的基础上,我们引入一个address表,该表记录person类的地址,address表的格式如下所示 现在person类要和address表想关联,得到当前联系人的住宅地址,我们应该 ...

  9. JavaWeb网上图书商城完整项目-数据库操作工具类

    1.首先安装数据库,在windows上安装和在unix上面安装环境不一样,我在自己的本地电脑上安装,安装成功之后,如果使用navicat远程工具访问,需要允许mysql远程能被访问 方法二.直接授权( ...

随机推荐

  1. Tomcat之端口占用问题的解决

    我们在使用Tomcat的时候经常会遇到端口占用的问题,如下图所示: 那么怎么解决这个问题呢? 第一步,你得知道什么占据了8080.8005.8009端口: 按win+R,输入cmd,打开命令行窗口,在 ...

  2. vSphere克隆虚机重启网卡报错

    使用VMware vSphere克隆虚机,修改IP重启网卡报错: 解决报错: 修改 /etc/udev/rules.d/70-persistent-net.rules 文件,克隆后会多出eth2和et ...

  3. 使用Minikube部署本地Kubernetes集群(二十八)

    前言 使用Minikube部署本地k8s集群相对比较简单,非常推荐将其用于本地k8s开发环境,唯一麻烦点的仅仅是网络问题. 在本篇教程中,我们使用了国内的镜像来完成本地k8s集群的搭建.如果搭建过程中 ...

  4. .Net高级编程-自定义错误页 web.config中<customErrors>节点配置

    错误页 1.当页面发生错误的时候,ASP.Net会将错误信息展示出来(Sqlconnection的错误就能暴露连接字符串),这样一来不好看,二来泄露网站的内部实现信息,给网站带来安全隐患,因此需要定制 ...

  5. 你必须了解的java内存管理机制(四)-垃圾回收

    本文在个人技术博客不同步发布,详情可用力戳 亦可扫描屏幕右侧二维码关注个人公众号,公众号内有个人联系方式,等你来撩... 相关链接(注:文章讲解JVM以Hotspot虚拟机为例,jdk版本为1.8) ...

  6. 文档管理器 PDFelement Pro v6.8.4.3921 精简绿色版

    下载地址:点我 PDFelement是PDF全套解决方案专家,专注于PDF的创建.编辑.转换.标注.保护.管理.水印.压缩.签名等功能.Wondershare PDFelement是款国产优秀的专业P ...

  7. 判断小端大端(C实现)

    C程序中的大端小端概念可以参见上一篇文章 如何区分小端和大端.本文重点讨论如何用C程序来判断当前系统是大端还是小端. 判断大端小端的程序如下: #include <stdio.h> int ...

  8. Linux系统-CENTOS7使用笔记

    复制文件夹下的所有文件到另一个文件夹下 cp ~/dirname/* ~/otherdirname 解压rar文件 PS:在liunx下原本是不支持rar文件的,需要安装liunx下的winrar版本 ...

  9. 第一章 Servlet

    JavaEEe技术包括Servlet/Jsp.Java Message Service(JMS).Enterprise JavaBeans(EJB).JavaServer Faces(JSF),以及J ...

  10. Junit简单的案例

    Calculator: public class Calculator { public double add(double number1, double number2) { return num ...