Redis(Remote Dictionary Server )即远程字典服务,是 C 语言开发的一个开源的key/value存储系统(官网:http://redis.io),是一个分布式缓存数据库。
官方只提供Linux版本,windows公司提供了Windows版的(Redis的次版本号(第一个小数点后的数字为偶数的版本是稳定版本,奇数为非稳定版本)
Redis作为一种key/value结构的数据存储系统,为了便于对数据进行进行管理,提供了多种数据类型,Reids中基础数据结构包含字符串、散列,列表,集合,有序集合
优势: 并发处理能力非常好 , 更好的保证数据的可靠性, 有丰富的数据类型
Bootnb 相关:https://www.runoob.com/redis/redis-tutorial.html Redis 官网:https://redis.io/ 源码地址:https://github.com/redis/redis Redis 在线测试:http://try.redis.io/ Redis 命令参考:http://doc.redisfans.com/
Redis数据存于磁盘中,采用TCP协议进行通讯
双写: 数据同时存入分布式缓存和数据库中
下载安装于linux操作系统中的docker容器中
基础常用命令常见数据类型 String数据类型启动及关闭redis服务
docker ps #查看进程 docker stop 618 #关闭进程 docker start redis #启动redis进程 ps -ef | grep redis # 查看正在运行的进程过滤redis进程 docker exec -it redis01 bash #redis01 为容器名 进入redis容器 redis-cli #登陆本地redis服务 或者 redis-cli -p 6379 或者 redis-cli -p 6379 -a password #-a后面为password,此操作需要开启redis.conf文件中的 requirepass选项 redis-cli -h ip -p 6379 -a password #登录远端redis服务 info #查看当前redis节点的详细配置信息 shutdown #保护模式关闭redis服务 exit #关闭redis服务select 1 #单机模式Redis默认支持16个数据库,下标是0-15 flushdb #清除当前数据库数据 flushall #清除所有数据库数据 set key1 100 #存入数据 type key1 #查看数据类型 ①set key2 100 EX 5 #设置数据存储的有效时长 EX秒 PX毫秒 ②set key3 100 expire key3 5 #数据保留5秒 ttl key3 #查看数据有效时长 keys * #查看当前数据库的所有key get key1 #查询key1的数据
Hash数据类型存储的值可以是字符串,其最大字符串长度支持到512M
于此类型,可以实现博客的字数统计,将日志不断追加到指定key,实现一个分布式自增id,实现一个博客的的点赞操作等set num 1 #如果值存在则覆盖 setnx num 9 #判断是否存在num,存在就不存入数据,不存在则存入数据 incr num #2 数据在内存中递增,数据库自增是在数据库程序中 订单分布式id incr num #3 如果num不存在,则自动会创建,如果存在自动+1 incrby num 2 #每次递增2 decr num #递减 decrby num 3 #每次递减3 del key1 key2 #删除 append test "abc" #向尾部追加值。如果键不存在则创建该键 strlen test #字符串长度,返回数据的长度,如果键不存在则返回0。注意,如果键值为空串,返回也是0 mset a 1 b 2 c 3 #同时设置/获取多个键值 mget a b c exists a b #判断某个值是否存在,0为不存在
List数据类型Redis散列类型相当于Java中的HashMap,实现原理跟HashMap一致,一般用于存储对象信息,存储了字段(field)和字段值的映射,K V中V又是KV结构
hset user username chenchen hset user password 123 hset user username chenchen password 123 hsetnx user password 456 hget user username hgetall user hmget user username password hvals user #chenchen 123 hkeys user #username password hincrby article total -1 #没有hdecrby自减命令 hexists user username hdel user username # 操作的是小key del user #操作的是大key
Set数据类型Redis的list类型相当于java中的LinkedList,其原理就就是一个双向链表。支持正向、反向查找和遍历等操作,插入删除速度比较快。经常用于实现热销榜,最新评论等的设计。K V 中的V为很多个有序可重复的V
lpush list1 a b c c d rpop list1 5 #a b c c d llen list1 #0 lpush list1 a b c c d lpop list1 5 #d c c b a lpush list1 a b c #最先进去的是最后的 linsert list1 before a f rpop list1 4 #a f b c lpush list1 a b c #c的下标是0 lset list1 0 g rpop list1 3 #a b g lpush num1 a b c lrem num1 1 a lrange num1 0 -1 #c b ltrim num1 0 0 lindex num 0 lpush g1 a b lpush g2 g f rpoplpush g2 g1 rpop g1 3 #a b g lpush num1 a b c brpop num1 20 #a 当元素移除完后,线程会指定阻塞时间20秒 brpop num1 20 #b brpop num1 20 #c
Zset数据类型Redis的Set类似Java中的HashSet,是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis中Set集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。K V 中的V为很多个无序不可重复的V
sadd set1 a a b b c c c d d smembers set1 #d b a c spop set1 1 #c spop set1 2 #a b sadd set1 a a b b c c c d d scard set1 #4 sadd set2 7 8 9 smove set1 set2 c spop set2 #7 c 8 9 sunion set1 set2
zet是Redis提供的一个非常特别的数据结构,常用作排行榜等功能,以用户d为value,关注时间或者分数作为score进行排序。K score1 user1 score2 user2
Java中操作redis
Redis 是一种C/S 架构的分布式缓存数据库,它有自带的命令行客户端,也有对应的Java或其它语言客户端,可以在这些客户端中通过一些API对redis进行读写操作。
创建父工程,pom文件添加编译配置
Jedis的基本应用org.apache.maven.plugins maven-compiler-plugin3.8.1 8 8
Jedis是Java中操作redis的一个客户端,类似通过jdbc访问mysql数据库.
创建redis-jedis 工程添加如下依赖
redis.clients
jedis
3.5.2
junit
junit
4.12
test
com.google.code.gson
gson
2.8.6
在Jedis工程中的src/test/java目录创建单元测类
public class JedisTests {
@Test
public void testHashOper01(){
//1.建立连接(TCP)
Jedis jedis=new Jedis(
"192.168.126.128", 6379);
//2.添加数据
Map map1=new HashMap<>();
map1.put("id", "201");
map1.put("title", "redis6.2.5");
jedis.hset("blog:201", map1);//不存在则直接添加
jedis.hset("blog:201", "title", "redis6.2.6");
//3.读取数据
map1=jedis.hgetAll("blog:201");
System.out.println(map1);
//4.释放资源
jedis.close();
}
@Test
public void testStringOper02() {
//1.建立连接
Jedis jedis=new Jedis(
"192.168.126.128", 6379);
//2.将一个map对象转换为json字符串,然后写入到redis并给定有效期
Map map1=new HashMap<>();
map1.put("id", "101");
map1.put("title", "redis6.2.5");
Gson gson=new Gson();
String jsonStr1=gson.toJson(map1);
System.out.println(jsonStr1);
jedis.set("blog:101", jsonStr1);
jedis.expire("blog:101", 20);
//3.从redis将json字符串读出,并转换为map然后输出.
String jsonStr2 = jedis.get("blog:101");
Map map2=gson.fromJson(jsonStr2,Map.class);
System.out.println(map2);
//4.释放资源
jedis.close();
}
@Test
public void testStringOper01(){
//1.建立连接
Jedis jedis=new Jedis(
"192.168.126.128", 6379);
//2.添加数据(Create)
jedis.set("id", "100");
Long setnx = jedis.setnx("lock", "AAA");
jedis.set("logs", "abc");
//3.获取数据(Retrieve)
String id = jedis.get("id");
System.out.println("update.before.id="+id);
//4.修改数据(Update)
jedis.incr("id");
id = jedis.get("id");
System.out.println("update.after.id="+id);
jedis.expire("lock", 10);
jedis.append("logs","EF");
//5.删除数据(Delete)
jedis.del("id");
id = jedis.get("id");
System.out.println("delete.after.id="+id);
//6.释放资源
jedis.close();
}
@Test
public void testGetConnection(){
//1.建立连接
//假如无法建立连接,要从如下几个方面进行分析
//1)ip
//2)port
//3)防火墙
//4)redis服务是否启动ok
Jedis jedis=new Jedis(
"192.168.126.128", 6379);
//jedis.auth("123456");
//2.执行ping操作
String result = jedis.ping();
System.out.println(result);
}
}
连接池JedisPool连接池
public class JedisPoolTests {
@Test
public void testJedisPool(){
//1.创建池对象
//GenericObjectPoolConfig poolConfig=
//new GenericObjectPoolConfig();
JedisPoolConfig poolConfig=//这个类型是上面类型的子类类型.
new JedisPoolConfig();
poolConfig.setMaxTotal(128);//最大连接数
poolConfig.setMaxIdle(8);//最大空闲连接数
JedisPool jedisPool=
//new JedisPool("192.168.126.128", 6379);
new JedisPool(poolConfig,
"192.168.126.128", 6379);
//2.获取连接
Jedis resource = jedisPool.getResource();
//3.读写数据
resource.set("id", "100");
String id = resource.get("id");
System.out.println(id);
//4.释放资源
resource.close();
jedisPool.close();//以后这个池是关服务的时候关.
}
}
提取连接池配置到配置类中,需要时直接通过方法获取即可
RedisTemplate基本应用(lettuceAPI)public class JedisDataSource { //初始化池对象并获取连接 (何时需要何时创建池对象~懒加载) private static volatile JedisPool jedisPool; public static Jedis getConnection(){ //JedisDataSource.class if(jedisPool==null) { synchronized (JedisDataSource.class) { if (jedisPool == null) { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(128);//最大连接数 poolConfig.setMaxIdle(8);//最大空闲连接数 jedisPool = new JedisPool(poolConfig, "192.168.126.128", 6379); //1.对象创建的过程? //1)分配内存 //2)初始化属性 //3)执行构造方法 //4)将JedisPool对象赋值给jedisPool变量 } } } return jedisPool.getResource(); } public static void close(){ jedisPool.close(); } }可以参考HikariDataSource类中连接池的创建,以上代码还是存在线程不停切换的问题,需要将成员变量赋值给局部变量,再进行判断,可以减少线程之间切换的问题; 还可以进一步优化,将连接池的配置参数提取到pom配置文件中
创建子工程redis-template,添加添加依赖
org.springframework.boot spring-boot-dependencies2.3.2.RELEASE pom import org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-data-redisorg.springframework.boot spring-boot-starter-testtest org.junit.vintage junit-vintage-enginemysql mysql-connector-javacom.baomidou mybatis-plus-boot-starter3.4.2 org.apache.commons commons-pool2
spring:
redis:
host: 192.168.126.129 #写自己的ip
port: 6379
创建启动类测试连接是否成功
package com.jt.redis;
@SpringBootTest
public class RedisTemplateTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void testGetConnection(){
RedisConnection connection =
redisTemplate.getConnectionFactory()
.getConnection();
String result = connection.ping();
System.out.println(result);
}
@Test
void testStringOper01(){
//1.获取字符串操作对象(ValueOperations)
ValueOperations vo = redisTemplate.opsForValue();
//2.操作redis数据
vo.set("x", 100);
Object x = vo.get("x");
System.out.println(x);
//vo.increment("x");//不可以
Long y = vo.increment("y");
y=vo.increment("y");
//Object y = vo.get("y");//不可以
System.out.println(y);
//存储key/value,设置key的有效期
vo.set("z", "100", Duration.ofSeconds(10));
}
@Test
void testStringOper02(){
//1.获取字符串操作对象(ValueOperations)
ValueOperations vo = redisTemplate.opsForValue();
//2.按默认序列化方式存储数据
String token= UUID.randomUUID().toString();
vo.set(token,"admin");
//3.指定序列方式进行数据存储
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setValueSerializer(RedisSerializer.string());
vo.set(token,"Mike");
//4.更新数据(假如有对应的key则直接进行覆盖)
vo.set(token, "Jack");
Object value = vo.get(token);
System.out.println(value);
//5.删除数据(存数据时给定有效期-生产环境必须设置)
vo.set("permissions", "sys:res:update",Duration.ofSeconds(5));
}
@Test
void testHashOper01(){
//1.获取Hash操作对象(ValueOperations)
HashOperations ho = redisTemplate.opsForHash();
//2.以hash类型存储数据
ho.put("blog","id",100);
ho.put("blog", "title", "redis....");
//3.获取数据
Object id = ho.get("blog", "id");
Object title = ho.get("blog", "title");
System.out.println("id="+id+";title="+title);
Map blog = ho.entries("blog");//取key对应的所有值。
System.out.println(blog);
}
@Test
void testHashOper02() throws JsonProcessingException {
//1.获取数据操作对象(ValueOperations,HashOperations)
ValueOperations vo = redisTemplate.opsForValue();
HashOperations ho = redisTemplate.opsForHash();
//2.基于ValueOperations存取Blog对象
Blog blog=new Blog();
blog.setId(100L);
blog.setTitle("redis ...");
vo.set("blog-jack", blog);//序列化
Object o = vo.get("blog-jack");//反序列化
System.out.println(o);
//3.基于HashOperations存取Blog对象
ObjectMapper objectMapper=new ObjectMapper();//jackson
String jsonStr=objectMapper.writeValueAsString(blog);
Map map = objectMapper.readValue(jsonStr, Map.class);
ho.putAll("blog-mike", map);
ho.put("blog-mike","id","200");
map=ho.entries("blog-mike");
System.out.println(map);
}
@Test
void testListOper(){
//向list集合放数据
ListOperations listOperations = redisTemplate.opsForList();
listOperations.leftPush("lstKey1", "100"); //lpush
listOperations.leftPushAll("lstKey1", "200","300");
listOperations.leftPush("lstKey1", "100", "105");
listOperations.rightPush("lstKey1", "700");
Object value= listOperations.range("lstKey1", 0, -1);
System.out.println(value);
//从list集合取数据
Object v1=listOperations.leftPop("lstKey1");//lpop
System.out.println("left.pop.0="+v1);
value= listOperations.range("lstKey1", 0, -1);
System.out.println(value);
}
@Test
void testSetOper(){
SetOperations setOperations=redisTemplate.opsForSet();
setOperations.add("setKey1", "A","B","C","C");
Object members=setOperations.members("setKey1");
System.out.println("setKeys="+members);
//........
}
@Test
void testFlushdb(){
redisTemplate.execute(new RedisCallback() {
@Override
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
//redisConnection.flushDb();
redisConnection.flushAll();
return "flush ok";
}
});
}
@Test
void testGetConnection(){
RedisConnection connection =
stringRedisTemplate.getConnectionFactory()
.getConnection();
String ping = connection.ping();
System.out.println(ping);
}
}



