1. Redis 笔记01
Redis 是非关系型数据库 ,数据与数据之间没有关联关系
Redis 命名规范
- key不要太长尽量不要超过1024k
- 在一个项目中,尽量使用统一的命名规范,例如user:123:password ; 不像mysql用_ Redis使用 :分割
- key名称区分大小写
例如: user🆔name 命名
user:1:zhangsan
user:2:lise
String 类型
- set key value 例如:set name zhangsan
- 如果频繁赋值,就将会覆盖掉原来的value,并且无视类型
- setnx key value 例如:setnx age 123; setnx age 456 ;get age 结果 123
是解决分布式锁的方式之一 - 取值命令 get key
- 取值命令 getrange 可选取值命令 例如: set name zhanghuihao; getrange name 0 4;
结果zhang 从0到44截取,从0开始 - strlen key 返回key 的长度 例如 set name zhang;
strlen name; 结果5 - expire key seconds 设置key的有效期 单位是s
- ttl key 查看当前key的有效时间 -2代表失效 -1代表永久有效
- getset key value 只能设置已经存在的key,不存在的key使用getset返回(nil).如果存在将会被重新赋值,但是会返回之前的value.例如:set name zhangsan; getset age 15 返回(nil) getset name zhanghuihao 返回(zhangsan),get name ;
值是zhanghuihao 会被重新赋值. - 删除命令(不限类型) del key
- 批量写 mset key1 value1 key2 value2 …
- 批量读 mget key1 key2 …
注意:只能针对数字的字符串
- incr key 每执行一次自增1 (从1开始) 例如:incr num;
get num ;值是1,再执行 incr num ; get num ;值是2 - decr key 同上自减
- incrby key [数字] 按照自定义的数字增加 例如 incrby num 10 ;值是10
- decrby key [数字] 同上
String类型运用场景:
String 类型通常用来保存单个字符串或者json字符串数字类型.String是二进制安全的,可以把图片文字的内容作为字符串存储.计数器 (常规计数,粉丝数,点赞数,微博数) 如果有100个用户同时对一个人进行点赞,点赞数不会发生变化。不会出现线程安全问题,因为 incr,decr,inceby,decrby命令都是原子性的。
Hash 类型
- hset key filed value ;hash类型相当于java中的hashset,hashset存储数据方式是key value ;而redis也是key value 故而(filed value)相当于 value
- hmset key filed value filed1 value1 同时在一个key 中存不同的字段值 和String类型不同
- hget key filed
- hmget key filed filed2 filed3 …
- hgetall key 把key中所有的(key-value)取出来
- del key 将整个key删除
- hdel key filed 删除key中某个(key-value)
- hlen key 查看 key中数据条数
- hkeys key 获取key中的所有字段(key)
- hsetnx key filed value 与 String类型一样
- hincrby key filed 3 某个filed自增3(只能是数字类型)
- hexists key filed 判断key中的某个key(字段)是否存在
- exists key 是判断key是否存在
应用场景
hash 应用场景 :存储一个用户信息对象数据
- 常用于存储一个对象
- 不用String存储需要反序列化 而且key太多浪费内存。
Jedis 客户端
- springboot 整合jedis,。pom注入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!--小辣椒-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--jedis-->
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
- yml文件/properties 配置jedisPool连接池连接信息。
server:
port: 8080
spring:
redis:
port: 6379
host: 192.168.60.128
password: 1234
jedis:
pool:
max-active: 10
min-idle: 2
max-idle: 6
- 创建JedisConf配置类 ,相当于xml文件配置,从yml读取配置信息
@Configuration //相当于xml配置文件
@PropertySource("classpath:application.yml ")
public class JedisConf {
//从yml文件中读取信息
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
private int timeout = 2000;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
@Value("${spring.redis.jedis.pool..min-idle}")
private int minIdle;
@Value("${spring.redis.jedis.pool..max-idle}")
private int maxIdle;
@Bean // <bean id ="jdedisPool" class = "redis.clients.jedis" > </bean>
public JedisPool jedisPoolFactory() {
System.out.println("JedisPool注入开始...");
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
jedisPoolConfig.setMaxTotal(maxActive);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout,password);
System.out.println("JedisPool注入成功...");
return jedisPool;
}
}
Jedis 操作Redis Sring类型数据
- redis有什么命令 jedis就有什么方法
- 模拟redis+mysql 先从redis中查询,如果存在取值 。不存在从mysql中查找,存在返回并且赋值给redis,下次查找直接从redis中找,缓解了mysql的压力。
- 代码如下:
service层
@Service
public class PersonServiceImpl implements PersonService {
@Autowired
private JedisPool jedisPool;
@Override
public String getString(String key) {
Jedis jedis = jedisPool.getResource(); //获取jedis对象
String value= "";
//redis如果存在直接取值
if(jedis.exists(key)){
value = jedis.get(key);
}else{
System.out.println("从mysql查询");
//查询到的值
value ="张慧豪";
//存在 赋值给redis
jedis.set(key,value);
}
jedis.close(); //关闭连接
return value;
}
}
/**
* 测试Sting 类型
* 需求:用户输入一个redis数据, 有效期是20s
* 模拟验证码
*/
@Override
public void expireStr(String key, String value) {
Jedis jedis = jedisUtil.getJedis();
jedis.set(key,value);
jedis.expire(key, 20);//long
jedisUtil.close(jedis);
}
Test类
@Autowired
private JedisPool jedisPool;
@Autowired
private PersonService personService;
/**
* 测试jedis操作Redis String类型数据
*/
@Test
void jedisString(){
System.out.println(jedisPool);
String value = personService.getString("name");
System.out.println(value);
}
/**
* 测试Redis key有效期
*/
@Test
void expireStr(){
String key ="phone";
String value="789456";
personService.expireStr(key,value);
}
Jedis操作 hash类型数据
工具类
@Component
public class JedisUtil {
@Autowired
JedisPool jedisPool;
public Jedis getJedis(){
return jedisPool.getResource();
}
public void close(Jedis jedis){
jedis.close();
}
}
service层
/**
* 需求:根据ID 查询用户信息
* 先从Redis中查找,如果存在返回
* 不存在,从Mysql中查找,返回并且赋值给Redis
*/
//#####################TODO Hash类型演示
@Override
public Person getPersonById(int id) {
Jedis jedis = jedisUtil.getJedis();
String key = "person"+":"+id; //Redis中key是person,mysql表是person
Boolean hexists = jedis.hexists(key,"id");
Person person = new Person();
if(hexists){
System.out.println("从Redis中查找");
Map<String, String> hgetAll = jedis.hgetAll(key);
person.setAddress(hgetAll.get("address"));
person.setAge(Integer.parseInt(hgetAll.get("age")));
person.setName(hgetAll.get("name"));
}else{
System.out.println("从Mysql中查找");
person.setAge(22);
person.setName("张三");
person.setAddress("太原");
HashMap<String, String> hash = new HashMap<>();
hash.put("id",id+"");
hash.put("age",String.valueOf(person.getAge()));
hash.put("name",person.getName());
hash.put("address",person.getAddress());
jedis.hmset(key,hash);
}
jedisUtil.close(jedis);
return person;
}
测试类
/**
* 测试Jedis 操作Redis Hash类型数据
*/
@Test
void getByid(){
Person personById = personService.getPersonById(1001);
System.out.println(personById.toString());
}
lettuce客户端
- springboot整合lettuce maven导入jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--redis 必须依赖pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
- 配置yml/properties文件
server:
port: 8081
spring:
redis:
port: 6379
host: 192.168.60.128
password: 1234
lettuce:
pool:
max-active: 10
max-idle: 6
min-idle: 2
timeout: 2000
- 写配置文件LettuceConf (注意:lettuce是引入的starter-data-redis jar包 springboot已经写好了配置类)
自动配置信息位置
spring-boot-autoconfigure:x.x.x.RELEASE
spring-boot-auoconfigure-x.x.x.RELEASE.jar
org.springframework.boot.autoconfigure
data
redis
RedisAutoConfiguration/RedisProperties
RedisAutoConfiguration配置信息:
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
但是自动配置的RedisTemplate<Object, Object> redisTemplate 不能满足用户要求,需要用户自己配置添加需求。例如:反序列化。
手动配置如下
@Configuration
public class RedisConfig {
@Bean //取代了RedisAutoConfiguration类中的 RedisTemplate
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
lettuce测试Redis中的String类型数据
Redis 有什么命令 jedis就有什么方法
* lettuce —> RedisTemplate 是对Jedis等客户端的进一步封装,故而与命令不对应
实体层
@Data
public class User {
private String id ;
private String name;
private String age;
}
service层
@Autowired
private RedisTemplate<Object,Object> redisTemplate;
/**
* Redis 有什么命令 jedis就有什么方法
* lettuce ---> RedisTemplate 是对Jedis等客户端的进一步封装,故而与命令不对应
* @return
*/
@Override
public String getString(String key) {
String value="";
if(redisTemplate.hasKey(key)) {
log.info("从Redis中获取值");
value = redisTemplate.opsForValue().get(key).toString();
}else{
log.info("从Mysql中获取值");
value="testStr";
System.out.println("查询到的值为"+value);
//存入到redis
redisTemplate.opsForValue().set(key,value);
}
return value;
}
/**
* 模拟时间 存 2小时 而Jedis只能针对秒
*/
public void saveVal(String key ,String value){
redisTemplate.opsForValue().set(key,value);
//2 timeunit 单位小时
redisTemplate.expire(key,2, TimeUnit.HOURS) ;
}
测试类
@Autowired
private RedisTemplate<Object,Object> redisTemplate;
@Autowired
private UserService userService;
@Test
void contextLoads() {
}
@Test
void testConn(){
System.out.println(redisTemplate);
}
@Test
void getStr(){
String user = userService.getString("user");
System.out.println(user);
}
@Test
void saveVal(){
userService.saveVal("phone","456789");
}