使用Redis和Java进行数据库缓存

举报
优锐课 发表于 2019/12/19 09:55:57 2019/12/19
【摘要】 本文来自国内专业IT教育学院【优锐课】。Java学习资料交流qq群:907135806,在接下来的学习如果过程中有任何疑问,欢迎进群探讨。使用Redis和Java探索数据库缓存,并查看一些不同的缓存策略。为什么数据库缓存如此重要?你在数据库中拥有的信息越多,随着时间的推移它将变得越慢。 即使是经过精心设计以支持许多并发请求的数据库管理系统,最终也会达到其极限。数据库缓存是处理这些性能问题的最...

本文来自国内专业IT教育学院【优锐课】。Java学习资料交流qq群:907135806,在接下来的学习如果过程中有任何疑问,欢迎进群探讨。

使用RedisJava探索数据库缓存,并查看一些不同的缓存策略。


为什么数据库缓存如此重要?

你在数据库中拥有的信息越多,随着时间的推移它将变得越慢。 即使是经过精心设计以支持许多并发请求的数据库管理系统,最终也会达到其极限。


数据库缓存是处理这些性能问题的最常见策略之一。缓存涉及将数据库查询的结果保存在更快,更易于访问的位置。正确完成缓存后,缓存将减少查询响应时间,减少数据库负载并降低成本。


但是,缓存也需要谨慎处理,因为它们实际上是在单独的位置中复制了你的另一份信息。保持数据库和缓存同步并保持最新状态可能是比你预期的棘手的挑战。在下一节中,我们将讨论一些最常见的数据库缓存策略。


有哪些不同的缓存策略?

手动缓存(也称为备用缓存策略)涉及对数据库和缓存的直接管理。你的应用程序在启动数据库查询之前检查缓存,并且在对数据库进行任何更改后都会更新缓存。


如果正确实施,手动缓存虽然有效,但可能非常繁琐,尤其是在需要查询多个数据库的情况下。由于这些原因,开发人员发明了许多替代的缓存策略。


Read-Through缓存策略

Read-Through中,应用程序首先查询缓存以查看其所需的信息是否在内部。如果不是,它将从数据库中检索信息并使用它来更新缓存。缓存提供程序或缓存库负责查询和更新缓存的详细逻辑。


当应用程序反复请求相同的数据时,Read-Through策略最适合于繁重的工作负载:例如,一个新闻网站一遍又一遍地加载相同的文章。


Read-Through策略的一个缺点是,对高速缓存的第一个查询将始终导致未命中,因为保证了所请求的信息不会在内部。为了解决此问题,开发人员通常会提前用用户可能会请求的信息“预热”缓存。


Write-Through 缓存策略

Write-Through缓存中,首先对缓存进行更新,然后对数据库进行更新。从应用程序到缓存以及从缓存到数据库都有一条直线。 Read-Through缓存结合使用时,Write-Through策略可确保你的数据保持一致,从而无需手动进行高速缓存失效。


Write-Behind缓存策略

Write-Behind缓存(也称为Write-Back缓存)中,应用程序首先将数据写入高速缓存。 经过一段时间的延迟后,高速缓存还将这些信息写入数据库。Write-Behind缓存最适合于繁重的写工作负载,即使出现一些故障和停机也可以表现良好。

 

使用Redisson的基于JavaRedis缓存

RedisNoSQL数据库中最受欢迎的选项之一,它使用键值系统存储数据。RedissonJava编程语言中Redis的客户端库,可使用所有熟悉的Java集合轻松访问Redis功能。


Redisson允许你将数据放置在外部存储的“地图”中。你可以使用此功能为数据库,Web服务或任何其他数据源实现缓存。


Redis中的Read-Through缓存

下面是一个Java示例,说明如何在RedisRedisson中使用Read-Through缓存。

如果请求的条目在缓存中不存在,它将由MapLoader对象加载:

MapLoader<String, String> mapLoader = new MapLoader<String, String>() {
    @Override
    public Iterable<String> loadAllKeys() {
        List<String> list = new ArrayList<String>();
        Statement statement = conn.createStatement();
        try {
            ResultSet result = statement.executeQuery("SELECT id FROM student");
            while (result.next()) {
                list.add(result.getString(1));
            }
        } finally {
            statement.close();
        }
        return list;
    }
    @Override
    public String load(String key) {
        PreparedStatement preparedStatement = conn.prepareStatement("SELECT name FROM student where id = ?");
        try {
            preparedStatement.setString(1, key);
            ResultSet result = preparedStatement.executeQuery();
            if (result.next()) {
                return result.getString(1);
            }
            return null;
        } finally {
            preparedStatement.close();
        }
    }
};



Configuration example:

MapOptions<K, V> options = MapOptions.<K, V>defaults()
                              .loader(mapLoader);
RMap<K, V> map = redisson.getMap("test", options);
// or
RMapCache<K, V> map = redisson.getMapCache("test", options);
// or with boost up to 45x times
RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
// or with boost up to 45x times
RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", options);



Redis 中的Write-Through缓存

下面是一个Java示例,说明如何在RedisRedisson中的Redis中使用Write-Through缓存。


直到MapWriter对象更新了缓存和数据库后,缓存更新方法才会返回:

MapWriter<String, String> mapWriter = new MapWriter<String, String>() {
    @Override
    public void write(Map<String, String> map) {
        PreparedStatement preparedStatement = conn.prepareStatement("INSERT INTO student (id, name) values (?, ?)");
        try {
            for (Entry<String, String> entry : map.entrySet()) {
                preparedStatement.setString(1, entry.getKey());
                preparedStatement.setString(2, entry.getValue());
                preparedStatement.addBatch();
            }
            preparedStatement.executeBatch();
        } finally {
            preparedStatement.close();
        }
    }
    @Override
    public void delete(Collection<String> keys) {
        PreparedStatement preparedStatement = conn.prepareStatement("DELETE FROM student where id = ?");
        try {
            for (String key : keys) {
                preparedStatement.setString(1, key);
                preparedStatement.addBatch();
            }
            preparedStatement.executeBatch();
        } finally {
            preparedStatement.close();
        }
    }
};



Configuration example:

MapOptions<K, V> options = MapOptions.<K, V>defaults()
                              .writer(mapWriter)
                              .writeMode(WriteMode.WRITE_THROUGH);
RMap<K, V> map = redisson.getMap("test", options);
// or
RMapCache<K, V> map = redisson.getMapCache("test", options);
// or with boost up to 45x times
RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
// or with boost up to 45x times
RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", options);



Redis 中的Write-Behind缓存

MapWriter接口还用于将更新异步提交到Map对象(缓存)和外部存储(数据库)。所有地图更新都分批累积,并以定义的延迟异步写入。


writeBehindDelay —批处理写入或删除操作的延迟。默认值为1000毫秒。


writeBehindBatchSize —批处理的大小。每批包含“映射条目”写入或删除命令。默认值为50


下面,我们看到一个Redisson中基于RedisWrite-Behind缓存实现的Java配置示例:

MapOptions<K, V> options = MapOptions.<K, V>defaults()
                              .writer(mapWriter)
                              .writeMode(WriteMode.WRITE_BEHIND)
                              .writeBehindDelay(5000)
                              .writeBehindBatchSize(100);
RMap<K, V> map = redisson.getMap("test", options);
// or
RMapCache<K, V> map = redisson.getMapCache("test", options);
// or with boost up to 45x times
RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
// or with boost up to 45x times
RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", options);


所有讨论的策略都可用于Redisson中的RMapRMapCacheRLocalCachedMapRLocalCachedMapCache对象。使用后两个对象可以使Redis中的读取操作快45倍。

 

本文来自国内专业IT教育学院【优锐课】


Java学习资料交流qq群:907135806,在接下来的学习如果过程中有任何疑问,欢迎进群探讨。也可以添加vx:ddmsiqi,有更多JVM、Mysql、Tomcat、Spring Boot、Spring Cloud、Zookeeper、Kafka、RabbitMQ、RockerMQ、Redis、ELK、Git等Java学习资料和视频课程干货分享!



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。