带Redis的Spring Boot:HashOperations CRUD功能

Spring Boot With Redis: HashOperations CRUD Functionality

介绍

远程字典服务器(Redis)是内存中的数据结构存储。 它可以用作简单的数据库,消息代理并通过对各种数据结构的支持进行缓存。

在本文中,我们将创建一个简单的CRUD应用程序并将Redis与Spring Boot集成。 要实现CRUD功能,我们将依靠Spring Data Redis项目提供的HashOperations接口。

雷迪斯

Redis是用C编写的开源内存中数据存储,这使它运行起来非常快。 由于其更快的读/写操作,因此通常用于缓存数据。 数据以键值形式存储在Redis中,其中使用键来提取值。

Redis还可以使用"快照"将数据保留在磁盘上,而不是将其保留在内存中-通过定期复制其内存数据存储区。

先决条件

安装Redis

Redis可以轻松地安装在Linux和macOS上。 但是,Windows需要一点技巧。 我们将在运行Ubuntu 18.04 LTS的AWS EC2实例上安装Redis:

1
$ sudo apt install redis-server

macOS,您可以通过brew安装它:

1
$ brew install redis

成功安装redis-server软件包后,让我们检查Redis进程的状态以验证安装:

1
$ systemctl status redis

结果显示redis-server的状态,绑定地址和正在监听redis-server的端口:

1
2
3
4
5
6
7
8
9
● redis-server.service - Advanced key-value store
   Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled)`
   Active: active (running) since Tue 2020-03-10 10:06:30 UTC; 3min 2s ago
     Docs: http://redis.io/documentation,
           man:redis-server(1)
 Main PID: 2227 (redis-server)
    Tasks: 4 (limit: 1152)
   CGroup: /system.slice/redis-server.service
           └─2227 /usr/bin/redis-server 127.0.0.1:6379

默认情况下,/etc/redis/redis.conf文件中将提供Redis配置。

启用与Redis的远程连接

默认情况下,只能从localhost访问Redis。 要启用到Redis服务器的远程连接,请将Redis配置中的绑定地址更新为0.0.0.0

1
bind 0.0.0.0 ::1

更新后,重新启动它:

1
$ systemctl restart redis

设置Spring Boot

从空白的Spring Boot应用程序开始的最简单方法是使用Spring Initializr:

spring boot initializr

另外,您也可以使用Spring Boot CLI引导应用程序:

1
$ spring init --dependencies=spring-boot-starter-data-redis redis-spring-boot-demo

我们从spring-boot-starter-data-redis依赖项开始,因为它包括spring-data-redisspring-boot-starterlettuce-core

如果您已经拥有Maven / Spring应用程序,则将依赖项添加到您的pom.xml文件中:

1
2
3
4
5
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>${version}</version>
</dependency>

或者,如果您使用的是Gradle:

1
compile group: 'org.springframework.data', name: 'spring-data-redis', version: '${version}'

连接到Redis服务器

与往常一样,在使用Redis等服务时,我们希望将应用程序连接到该服务。 提供了多个基于Java的Redis连接器-Jedis和Lettuce是两个流行的选项。

与Jedis联系

要使用Jedis,我们必须将其添加到我们的pom.xml文件中:

1
2
3
4
5
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>${version}</version>
</dependency>

或者,如果您使用的是Gradle:

1
compile group: 'redis.clients', name: 'jedis', version: '${version}'

依赖关系到位后,我们需要设置JedisConnectionFactory

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class Config {
    @Bean
    public JedisConnectionFactory redisConnectionFactory() {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setHostName("your_host_name_or_ip");
        jedisConnectionFactory.setPort(6379);
        jedisConnectionFactory.afterPropertiesSet();
        return jedisConnectionFactory;
    }
}

不用说,此设置是在@Configuration类中执行的。 如果您想了解有关Spring Framework核心注释的更多信息,我们将为您服务!

与Lettuce连接

Lettuce是基于Netty的开源Redis连接器,与启动程序相关性打包在一起。 Lettuce连接工厂的设置与Jedis几乎相同:

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class Config {
    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        LettuceConnectionFactory lcf = new LettuceConnectionFactory();
        lcf.setHostName("your_host_name_or_ip");
        lcf.setPort(6379);     
        lcf.afterPropertiesSet();
        return lcf;
    }
}

尽管它们的设置几乎相同,但是用法不同。 例如,与Jedis不同,Lettuce允许异步操作并且是线程安全的。

Redis模板

RedisTemplate是Spring Data提供的条目类,通过它我们与Redis服务器进行交互。

我们将RedisConnectionFactory实例传递给RedisTemplate以建立连接:

1
2
3
4
5
6
public static RedisTemplate<String, User> redisTemplate() {
    RedisTemplate<String, User> redisTemplate = new RedisTemplate<String ,User>();
    redisTemplate.setConnectionFactory(redisConnectionFactory());
    redisTemplate.afterPropertiesSet();
    return redisTemplate;
}

一旦建立,RedisTemplate将成为我们可以命令的Redis操作的主要抽象。 它还负责将对象序列化和反序列化为字节数组。

默认情况下,RedisTemplate使用JdkSerializationRedisSerializer来序列化和反序列化对象。

可以更改RedisTemplate的序列化机制,Redis在org.springframework.data.redis.serializer包中提供了几个序列化器。

StringRedisTemplateRedisTemplate的扩展,例如专注于基于字符串的键值对。

为了支持对不同数据类型的各种操作,RedisTemplate提供了诸如ValueOperationsListOperationsSetOperationsHashOperationsStreamOperations等的操作类。

对于与哈希相关的操作(将用于在Redis服务器中存储数据),我们将使用HashOperations类。

哈希操作

Redis哈希可以容纳n个键-值对,并且设计为使用较少的内存,这使其成为在内存中存储对象的好方法。 通过HashOperations辅助类,我们可以对其进行操作。

要使用这些方法中的任何一种,我们将从RedisTemplate实例返回的哈希操作打包到HashOperations接口中:

1
HashOperations hashOperations = redisTemplate.opsForHash();

这些操作包括基本的哈希映射操作,例如put()get()entries()等:

1
2
// Sets user object in USER hashmap at userId key
hashOperations.put("USER", user.getUserId(), user);

1
2
// Get value of USER hashmap at userId key
hashOperations.get("USER", userId);

1
2
// Get all hashes in USER hashmap
hashOperations.entries("USER");

1
2
// Delete the hashkey userId from USER hashmap
hashOperations.delete("USER", userId);

定义用户存储库

现在,让我们继续创建一个用户存储库,该存储库实际上将处理CRUD操作:

1
2
3
4
5
6
7
@Repository
public class UserRepository {
    private HashOperations hashOperations;
    public UserRepository(RedisTemplate redisTemplate) {
        this.hashOperations = redisTemplate.opsForHash();
    }
}

相比之下,在典型的存储库中,HashOperations类似于SessionFactory。 使用Redis,您还可以通过扩展CrudRepository接口并在@Bean中设置Jedis连接来建立存储库。

在构造函数中,我们传递我们的redisTemplate,应使用Redis连接工厂对其进行配置。

现在,要输入一个条目,我们将使用:

1
hashOperations.put("USER", hashKey, value);

单个键(例如USER)可以具有多个hashKey:value对。 每个value可以通过hashKey访问给定密钥。

或获取条目,我们将使用:

1
value = hashOperations.get("USER", hashKey);

让我们定义User

1
2
3
4
5
6
public class User {
    private int userId;
    private String name;
   
    // Constructor, getters and setters
}

考虑到这一点,让我们实现存储库的其余部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Repository
public class UserRepository {
   
    final Logger logger = LoggerFactory.getLogger(UserRepository.class);
    private HashOperations hashOperations;
   
    public UserRepository(RedisTemplate redisTemplate) {
        this.hashOperations = redisTemplate.opsForHash();
    }
   
    public void create(User user) {
        hashOperations.put("USER", user.getUserId(), user);
        logger.info(String.format("User with ID %s saved", user.getUserId()));
    }
   
    public User get(String userId) {
        return (User) hashOperations.get("USER", userId);
    }

    public Map<String, User> getAll(){
        return hashOperations.entries("USER");
    }
   
    public void update(User user) {
        hashOperations.put("USER", user.getUserId(), user);
        logger.info(String.format("User with ID %s updated", user.getUserId()));
    }
   
    public void delete(String userId) {
        hashOperations.delete("USER", userId);
        logger.info(String.format("User with ID %s deleted", userId));
    }
}

现在测试应用程序,让我们使用userRepository

1
2
3
4
5
6
UserRepository userRepository = new UserRepository(redisTemplate());

userRepository.create(new User("1","username","emailid"));
User user = userRepository.get("1");
userRepository.update(user);
userRepository.delete(user.getUserId());

运行这段代码将产生:

1
2
3
2020-03-30 11:34:11.260  INFO 8772 --- [           main] c.h.redistutorial.UserRepository       : User with ID 1 saved
2020-03-30 11:34:11.260  INFO 8772 --- [           main] c.h.redistutorial.UserRepository       : User with ID 1 updated
2020-03-30 11:34:11.260  INFO 8772 --- [           main] c.h.redistutorial.UserRepository       : User with ID 1 deleted

让我们使用Redis客户端查看正在插入,更新和删除的数据。

  • 创建用户:created user in redis

    创建用户:
    created user in redis

    更新用户:
    get user from redis

    删除用户:
    user deleted from redis

    结论

    由于Spring Boot轻巧且易于使用,因此越来越受到Java / Spring开发人员的青睐。 它极大地简化了引导应用程序的过程,并帮助您将精力集中在实际的业务逻辑上,而不是将它们连接在一起。

    另一方面,Redis是一个非常流行的内存数据库,使其成为微服务的绝佳伴侣。

    Redis通常由微服务用于缓存管理,以减少对服务器的数据库调用次数。 在按使用付费的收费系统的新世界中,这可以有效地降低企业和企业的运营成本。