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

为何数据库缓存如此重要?

您在数据库中得到的信息越多,随着时间的推移它就越慢。即便是为支持许多并发请求而精心设计的数据库管理系统也将最终达到极限。html

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

可是,缓存也须要当心处理,由于它们其实是在另外一个位置建立另外一个信息副本。保持数据库和缓存同步并保持最新可能比您预期的更棘手。在下一节中,咱们将讨论一些最多见的数据库缓存策略。git

什么是不一样的缓存策略?

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

虽然若是正确实现有效,但手动缓存可能很是繁琐,尤为是在您须要查询多个数据库时。出于这些缘由,开发人员发明了许多替代缓存策略。redis

直读缓存策略

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

当应用程序重复请求相同的数据时,读取策略最适合读取繁重的工做负载:例如,一遍又一遍地加载相同文章的新闻网站。编程

读取策略的一个缺点是对缓存的第一次查询将始终致使未命中,由于保证所请求的信息不在内部。为了解决这个问题,开发人员一般会使用用户可能要求的信息提早“加热”缓存。api

直写缓存策略

在直写式高速缓存中,首先对高速缓存进行更新,而后对数据库进行更新。从应用程序到缓存以及从缓存到数据库都有一条直接线。与直读式缓存结合使用时,直写式策略可确保您的数据保持一致,从而无需手动缓存失效。缓存

后写式缓存策略

在后写式缓存(也称为回写式高速缓存)中,应用程序首先将数据写入高速缓存。通过一段设定的延迟后,缓存也会将此信息写入数据库。后写缓存最适合写入繁重的工做负载,即便出现一些故障和停机也能够很好地执行。bash

基于Java的Redis缓存与Redisson

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

Redisson容许您将数据放在外部存储中的map中。您可使用此功能实现数据库,Web服务或任何其余数据源的缓存。

Redis中的直读缓存

下面是一个Java示例,说明如何在Redis和Redisson中使用直读缓存。

若是请求的条目在缓存中不存在,则它将由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();
        }
    }
};
复制代码

配置示例:

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中的直写缓存

下面是一个Java示例,说明如何在Redis中使用MapWriter直写缓存。

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();
        }
    }
};
复制代码

配置示例:

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中的后写缓存

MapWriter接口还用于异步提交对Map对象(缓存)和外部存储(数据库)的更新。全部映射更新都按批次累积,并以定义的延迟异步写入。

writeBehindDelay
- 批量写入或删除操做的延迟。默认值为1000毫秒。

writeBehindBatchSize
- 批量大小。每一个批处理包含Map Entry写入或删除命令。默认值为50。

下面,咱们看到Redisson中基于Redis的后写缓存实现的配置的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 中的RMapCache,RLocalCachedMap和RLocalCachedMapCache对象实现。使用后两个对象可使Redis中的读取操做速度提升45倍。

英文原文:dzone.com/articles/da…

查看更多文章:www.apexyun.com

公众号:银河系1号

联系邮箱:public@space-explore.com

(未经赞成,请勿转载)

相关文章
相关标签/搜索