Redis与Mysql都是数据库,Redis是非关系型数据库,Mysql是关系型数据库
对于关系型数据库存在Java的数据库连接:JDBC
Jedis就类似于JDBC,是Redis官方首选的Java客户端开发包,Jedis就是集成了redis的一些命令操作,封装了redis的java客户端
我们可以写一个简单的Jedis命令:
<!--Jedis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
name:lisi
数据 @Test
void test4(){
Jedis jedis = new Jedis("localhost",6379);
String name = jedis.get("name");
System.out.println(name);
jedis.close();
}
Jedis集成了redis的一些命令操作,封装了redis的java客户端,从它的方法也可以看出:都是Redis的命令
每个Jedis实例对应一个Redis节点,Jedis实例的操作相当于启动redis-cli客户端操作
就如同我们不会直接使用JDBC连接数据库,而是使用数据库连接池如dbcp、c3p0等
Jedis也为我们提供了Jedis的池化技术,JedisPool在创建时初始化一些连接资源存储到连接池中,使用Jedis连接资源时不需要创建,而是从连接池中获取一个资源进行redis的操作,使用完毕后,不需要销毁该jedis连接资源,而是将该资源归还给连接池,供其他请求使用
JedisPool类提供了很多构造方法,用于设置连接池的属性
GenericObjectPoolConfig配置类用于封装连接池属性:最大空闲数、最大连接数等
后续参数有:host地址,port端口号,timeout超时时间,password数据库密码等
通过这些参数连接Redis,配置连接池参数,可以使连接池有效的管理Redis连接
项目:因为这里只整合Redis,即只使用config配置类,User实体类,service服务层,Redis做缓存用
在applicat.yml中可以设置Jedis:
spring:
redis:
host: ip地址
password: 密码
port: 6379
timeout: 20000 #超时连接
jedis:
pool:
max-idle: 6 #最大空闲数
max-active: 10 #最大连接数
min-idle: 2 #最小空闲数
Spring也提供了很多Redis的配置:
以及Jedis配置:
我们需要获得这些属性封装到配置类中,返回bean:JedisPool
package com.learn.jedis.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* Author : zfk
* Data : 17:28
*/
@Configuration
public class JedisConfig {
private Logger logger = LoggerFactory.getLogger(JedisConfig.class);
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Bean
public JedisPool jedisPool(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxTotal(maxActive);
jedisPoolConfig.setMinIdle(minIdle);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password);
logger.info("JedisPoll连接成功:"+host+"\t"+port);
return jedisPool;
}
}
实体类:
package com.learn.jedis.po;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* Author : zfk
* Data : 17:20
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private String id;
private String name;
private Integer age;
}
对应Redis中Hash类型的数据:user:1 {id:1,name:lisi,age:26}
服务层UserService:
package com.learn.jedis.service;
import com.learn.jedis.po.User;
/**
* Author : zfk
* Data : 19:37
*/
public interface UserService {
public User selectById(String id);
}
UserServiceImpl:
package com.learn.jedis.service;
import com.learn.jedis.po.User;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.HashMap;
import java.util.Map;
/**
* Author : zfk
* Data : 19:40
*/
@Service
@Log
public class UserServiceImpl implements UserService {
//Redis - Jedis连接池
@Autowired
private JedisPool jedisPool;
/**
* Redis - Hash类型
* 存一个对象
* 用户在前端传入一个ID编号,查询用户对象
* 先到Redis查询,如果Redis存在直接返回结果
* 不存在就查询Mysql(模拟),返回查询结果,赋值给Redis
*/
@Override
public User selectById(String id){
//key => 表名:id
String key ="user:"+id;
//得到Jedis对象
Jedis jedis = jedisPool.getResource();
User user = null;
//判断
if (jedis.exists(key)){
//存在,打印输出
log.info("=== 查询Redis数据库 ===");
Map<String, String> map = jedis.hgetAll(key);
user = new User(map.get("id"), map.get("name"), Integer.parseInt(map.get("age")));
}
else {
log.info("=== 查询Mysql数据库 ===");
user = new User(id,"张三",19);
HashMap<String, String> map = new HashMap<>();
map.put("id",user.getId());
map.put("name",user.getName());
map.put("age",user.getAge().toString());
jedis.hmset(key,map);
log.info("=== 存入Redis中 ===");
}
return user;
}
测试类:
package com.learn.jedis;
import com.learn.jedis.po.User;
import com.learn.jedis.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@SpringBootTest
class JedisApplicationTests {
@Autowired
private UserService userService;
@Test
void test3(){
User user = userService.selectById("1111");
System.out.println(user.toString());
}
}
第一次查询id=1111的用户,不存在,赋值给Redis
码云
Jedis现在只在比较老的项目上了
SpringBoot2.x起,默认使用Lettuce
Lettuce 和 Jedis 都是Redis的client:redis-cli
Jedis在实现上是直接连接的Redis Server,如果在多线程环境下是非线程安全的。 每个线程都去拿自己的 Jedis 实例,当连接数量增多时,资源消耗阶梯式增大,连接成本就较高了。Lettuce的连接是基于Netty的,Netty 是一个多线程、事件驱动的 I/O框架。连接实例可以在多个线程间共享,当多线程使用同一连接实例时,是线程安全的。