用泛型写Redis缓存与数据库操作工具类

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

        如果数据库中没有数据,需要设置一个缓存标记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);
        }

    }

}

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

原文地址:https://www.cnblogs.com/itbac/p/11210414.html

时间: 2024-07-31 22:44:25

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

android greenDao SQLite数据库操作工具类使用

上一篇介绍了如何建立类生成工程,现在介绍如何使用. 以下是ExampleDaoGenerator工程代码,做了一些修改 /* * Copyright (C) 2011 Markus Junginger, greenrobot (http://greenrobot.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in com

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

工作中,经常会遇到缓存和数据库数据一致性问题.从理论上设置过期时间,是保证最终一致性的解决方案.这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可.也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存.因此,接下来讨论的思路不依赖于给缓存设置过期时间这个方案. 在这里,我们讨论三种更新策略: 1) 先更新数据库,再更新缓存 2) 先删除缓存,再更新数据库 3) 先更新数据库,再删除缓

面向对象编程、模块内高内聚、模块间低耦合、数据库操作工具类

一.web.config帮助类(ConfigHelper.cs) 1 using System; 2 using System.Collections.Generic; 3 using System.Configuration; 4 using System.Reflection; 5 6 namespace Common 7 { 8 /// <summary> 9 /// web.config操作类 10 /// author:陈彦斌 11 /// 时间:2019年7月14日23:32:08

redis缓存与数据库一致性问题

一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求和写请求串行化,串到一个内存队列里去. 串行化可以保证一定不会出现不一致的情况,但是它也会导致系统的吞吐量大幅度降低,用比正常情况下多几倍的机器去支撑线上的一个请求. Cache Aside Pattern 最经典的缓存+数据库读写的模式,就是 Cache Aside Pattern. 读的时候,先读缓存,缓存没有的话,就读数据库,然后

Redis缓存与数据库数据一致性

转自:https://blog.kido.site/2018/11/24/db-and-cache-preface/ 方案一 写流程:先删除缓存,删除之后再更新DB,再异步将数据刷回缓存.如果先更新数据库再更新缓存,更新数据库时,程序访问缓存时还是旧的数据. 读流程:先读缓存,如果缓存没读到,则去读DB,之后再异步将数据刷回缓存. 缺点: 容灾不足 第一步DEL缓存失败’,如果继续执行,那么从’更新完DB’到异步’刷新缓存’缓存期间,数据处于滞后状态.而且如果缓存处于不可写状态,那么异步刷新那步

怎么保证缓存和数据库数据的一致性?

参考链接:Redis缓存和数据库一致性问题 缓存与数据库一致性之一:缓存更新设计 原文地址:https://www.cnblogs.com/jxxblogs/p/12243035.html

Asp.Net Core 2.0 项目实战(6)Redis配置、封装帮助类RedisHelper及使用实例

本文目录 1. 摘要 2. Redis配置 3. RedisHelper 4.使用实例 5. 总结 1.  摘要 由于內存存取速度远高于磁盘读取的特性,为了程序效率提高性能,通常会把常用的不常变动的数据存储在系统内存中,提升数据读取的速度,在C#下常见的内存操作有微软自带的内存处理.分布式缓存Memcached以及Redis,这里我们介绍Redis分布式缓存,另外两种缓存处理参考<Asp.Net Core 2.0 项目实战(8)Core下缓存操作.序列化操作.JSON操作等Helper集合类>

开发自己的框架——(二)数据库工具类的封装

为了让框架的内容与数据分离,我们把常用的类封装到一个工具类中,当用到这些方法时,就调用这个封装好的类,能够使代码的复用性得到很大的提高.首先,封装数据库相关操作,为了使封装规范化,我们创建一个接口让数据库实现接口中的方法,数据库使用PDO扩展访问数据.数据库接口类 I_DAO.interface.php 1 <?php 2 interface I_DAO 3 { 4 //查询所有数据的功能 5 public function getAll($sql=''); 6 // //查询一条数据 7 pu

数据库操作类,链式操作

<?php define('MY_DBHOST', 'localhost'); define('MY_PORT', '3306'); define('MY_DBUSER', 'root'); define('MY_DBPW', '123456'); define('MY_DBNAME', 'test'); define('MY_DBCHARSET', 'utf8'); define('MY_DBTABLEPRE', 'pre_'); function M($table,$database='',