Redis--Jedis应用与Spring Boot整合Redis
Redis缓存
Jedis客户端
Jedis是一个基于Java的Redis客户端连接工具,旨在提升性能与易用性。其地址是:https://github.com/redis/jedis。
创建工程
创建一个普通maven工程,然后在pom文件添加以下依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
使用Jedis
Jedis的方法名几乎与Redis命令相同。每次使用时直接创建Jedis实例即可。
Jedis实例创建之后,其底层会创建一个指定Redis服务器的Socket连接,所以为了节省资源,每次使用完Jedis实例后,要立即调用close()方法关闭连接。
value为String
@Test
public void test() {
Jedis jedis = new Jedis("192.168.220.128", 6379);
jedis.set("name", "Alice");
jedis.mset("age", "18","depart","IT");
String value = jedis.get("name");
System.out.println("Value for 'name': " + value);
jedis.close();
}
value为Hash
@Test
public void test2() {
Jedis jedis = new Jedis("192.168.220.128", 6379);
jedis.hset("employee", "name", "Bob");
Map<String, String> employeeData = new HashMap<>();
employeeData.put("age", "30");
employeeData.put("department", "IT");
jedis.hset("employee", employeeData);
String name = jedis.hget("employee", "name");
List<String> emp=jedis.hmget("employee", "department","age");
System.out.println("Employee Name: " + name);
System.out.println("Employee Department: " + emp.get(0));
System.out.println("Employee Age: " + emp.get(1));
jedis.close();
}
value为List
@Test
public void test3() {
Jedis jedis = new Jedis("192.168.220.128", 6379);
jedis.rpush("names", "ali", "Bob", "Charlie");
List<String> employees = jedis.lrange("names", 0, -1);
System.out.println("Employees: " + employees);
jedis.close();
}
value为set
@Test
public void test4() {
Jedis jedis = new Jedis("192.168.220.128", 6379);
jedis.sadd("midWares", "Redis", "Nginx", "RocketMQ");
Set<String> employees = jedis.smembers("midWares");
System.out.println("Employees: " + employees);
jedis.close();
}
value为ZSet
@Test
public void test5() {
Jedis jedis = new Jedis("192.168.220.128", 6379);
jedis.zadd("scores", 90, "Alice");
jedis.zadd("scores", 85, "Bob");
jedis.zadd("scores", 95, "Charlie");
jedis.zadd("scores", 33, "Harry");
jedis.zadd("scores", 31, "Oliver");
// 获取前三个员工的名字
List<String> employees = jedis.zrevrange("scores", 0, 2);
System.out.println("Top3: " + employees);
List<Tuple> scores = jedis.zrevrangeWithScores("scores", 0, -1);
for (Tuple tuple : scores) {
System.out.println(tuple.getScore()+":"+tuple.getElement());
}
jedis.close();
}
使用JedisPool
频繁的创建和销毁Jedis实例,虽然节省系统资源和网络带宽,但会降低系统性能,因为创建和销毁连接比较耗时,此时可以使用Jedis连接池来解决该问题。
JedisPool是全局性的,整个类只需要创建一次即可,然后每次操作Redis时,从JedisPool中拿出一个Redis实例即可。使用完毕无需释放Redis实例,返回给JedisPool即可。
public class JedisPoolTest {
private JedisPool pool = new JedisPool("192.168.220.128", 6379);
@Test
public void test() {
try (Jedis jedis = pool.getResource()) {
jedis.set("name", "Alice");
String value = jedis.get("name");
System.out.println("Value for 'name': " + value);
}
}
}
使用JedisPooled
每次对Redis操作都需要使用try-with-resource块比较麻烦,使用JedisPooled 就无需使用该结构来释放资源了。
public class JedisPooledTest {
private JedisPooled pool = new JedisPooled("192.168.220.128", 6379);
@Test
public void test() {
pool.set("name", "Alice");
String value = pool.get("name");
System.out.println("Value for 'name': " + value);
}
}
连接Sentinel高可用集群
直接使用JedisSentinelPool即可。
在该客户端只需注册Sentinel节点及其监控的Master的名称即可,无需出现master-slave的任何地址信息。
其采用的也是JedisPool,使用完毕需要通过close()方法将其返回给连接池。
public class JedisSentinelPoolTest {
private JedisSentinelPool pool;
{
HashSet<String> sentinels = new HashSet<>();
sentinels.add("redis:26380");
sentinels.add("redis:26381");
sentinels.add("redis:26382");
pool=new JedisSentinelPool("mymaster",sentinels);
}
@Test
public void test() {
try (Jedis jedis = pool.getResource()) {
jedis.set("name", "Alice");
String value = jedis.get("name");
System.out.println("Value for 'name': " + value);
}
}
}
连接分布式系统
使用JedisCluster即可。
底层采用的也是Jedis连接池技术,每次使用完毕无需显示关闭,其会自动关闭。
JedisCluster常用的构造器有两个:
-
只需一个集群节点的构造器。
这个节点可以是集群中的任意节点,只要连上该节点,就连上了整个集群。
但是这样会存在一个问题:如果连接之前这个节点恰好宕机,那么就连不上集群了。所以不推荐使用。
-
将集群中所有节点罗列出来。这样就避免了这种风险。
public class JedisClusterTest {
private JedisCluster jedisCluster;
{
HashSet<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("127.0.0.1",6380));
nodes.add(new HostAndPort("127.0.0.1",6381));
nodes.add(new HostAndPort("127.0.0.1",6382));
nodes.add(new HostAndPort("127.0.0.1",6383));
nodes.add(new HostAndPort("127.0.0.1",6384));
nodes.add(new HostAndPort("127.0.0.1",6385));
nodes.add(new HostAndPort("127.0.0.1",6386));
nodes.add(new HostAndPort("127.0.0.1",6387));
jedisCluster = new JedisCluster(nodes);
}
@Test
public void test() {
jedisCluster.set("name", "Alice");
String value = jedisCluster.get("name");
System.out.println("Value for 'name': " + value);
}
}
操作事务
Jedis提供了multi()、watch()、unwatch()来对应Redis中的multi、watch、unwatch命令。
Jedis的multi()返回一个Transaction对象,其exec()和discard()用于执行和取消事务。
抛出Java异常
public class JedisTxTest {
private JedisPool jedisPool = new JedisPool("192.168.220.128",6379);
@Test
public void test() {
try (Jedis jedis = jedisPool.getResource()) {
jedis.set("name", "Alice");
jedis.set("age", "30");
Transaction tx = jedis.multi();
try {
tx.set("name", "Bob");
int i= 3/0;
tx.set("age", "25");
tx.exec();
} catch (Exception e) {
System.out.println("Transaction failed: " + e.getMessage());
tx.discard();
} finally {
String name = jedis.get("name");
String age = jedis.get("age");
System.out.println("Name: " + name);
System.out.println("Age: " + age);
}
}
}
}
输出结果是全部回滚的结果!

抛出Redis异常
@Test
public void test2() {
try (Jedis jedis = jedisPool.getResource()) {
jedis.set("name", "Alice");
jedis.set("age", "30");
Transaction tx = jedis.multi();
try {
tx.set("name", "Bob");
tx.incr("name");
tx.set("age", "25");
tx.exec();
} catch (Exception e) {
System.out.println("Transaction failed: " + e.getMessage());
// redis异常不会被Java代码捕获到。
tx.discard();
} finally {
String name = jedis.get("name");
String age = jedis.get("age");
System.out.println("Name: " + name);
System.out.println("Age: " + age);
}
}
}
输出结果如下:

说明Redis运行时异常不会被java捕获到,不影响代码的运行。
watch()
@Test
public void test3() {
try (Jedis jedis = jedisPool.getResource()){
jedis.set("age", "30");
System.out.println("加1前的值是:"+jedis.get("age"));
jedis.watch("age");
Transaction tx = jedis.multi();
tx.incr("age");
tx.exec();
System.out.println("加1前的值是:"+jedis.get("age"));
}
}
SpringBoot整合Redis
Spring Boot中一般使用RedisTemplate 类来操作Redis。
-
创建SpringBoot项目
-
添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> -
在配置文件中增加Redis相关配置
spring: # 配置单机版Redis redis: host: localhost port: 6379 password: 1111 # # 配置Sentinel高可用集群 # sentinel: # master: mymaster # nodes: # - localhost:26380 # - localhost:26381 # - localhost:26382 # # 配置分布式系统 # cluster: # nodes: # - localhost:6380 # - localhost:6381 # - localhost:6382 # - localhost:6383 # - localhost:6384 # - localhost:6385 # 配置缓存 cache: type: redis cache-names: pc -
修改实体类
注意:要将实体类缓存到Redis,实体类必须序列化,所以要实现序列化接口 Serializable。
-
修改具体的实现类,主要修改写操作方法和读操作方法。
写操作的方法如下:
@Autowired private RedisTemplate<String, Object> redisTemplate; @Autowired private ProductDao productDao; @Transactional // @CacheEvict 用于实现value指定缓存空间中缓存数据的清空。allEntries为true表示清空该缓存空间中的所有数据。 // 如果不想清空所有,可以通过key属性指定要清空的缓存数据的key。 @CacheEvict(value = "pc", allEntries = true) public void saveProduct(Product product) { productDao.save(product); }读操作的方法如下:
// @Cacheable 用于实现方法的结果进行缓存。value指定缓存空间,key指定缓存数据的key。 // 如果缓存中存在指定key的数据,则直接返回缓存中的数据;如果不存在,则执行方法体中的代码,并将结果存入缓存中。 @Cacheable(value = "pc", key = "'product_all'") public List<Product> getAllProducts() { return productDao.findAll(); } // #name 表示方法参数name的值。也可以使用#root.args[0]来表示第一个参数的值。 @Cacheable(value = "pc", key = "'product_'+#name") public Product getProductByName(String name) { return productDao.findByName(id); } @Autowired private RedisTemplate<String, Object> redisTemplate; // 获取营业额的方法,适用于方法中获取缓存的值再参与计算的场景 public Double findTurnover(){ // 从Redis中获取营业额数据 BoundValueOperations<String, Object> opsForValue = redisTemplate.boundValueOps("turnover"); // get方法的参数是要获取的缓存数据的key,这里假设营业额数据的key为"turnover" Double turnover = (Double) opsForValue.get(); if (turnover == null) { // 如果Redis中没有数据,则从数据库中查询并存入Redis turnover = queryTurnoverFromDatabase(); opsForValue.set(turnover,10, TimeUnit.MINUTES); // 将营业额数据存入Redis,设置过期时间为10分钟 } return turnover; } -
修改Application启动类
@EnableCaching @SpringBootApplication public class SpringbootRedisApplication { public static void main(String[] args) { SpringApplication.run(SpringbootRedisApplication.class, args); } }@EnableCaching 用于开启当前应用的缓存功能。
总结如何将SpringBoot 与Redis整合?
- POM中导入依赖
- 在配置文件中注册Redis连接信息与缓存信息
- 需要缓存的实体类必须实例化
- 在启动类上加@EnableCaching 注解
- 查询方法上加@Cacheable注解
- 写操作方法上加@CacheEvict注解
- 需要手动操作Redis方法,需要通过RedisTemplate 来获取操作对象
本文来自博客园,作者:NE_STOP,转载请注明原文链接:https://www.cnblogs.com/alineverstop/p/20014985
浙公网安备 33010602011771号