1、Redis缓存
1.1、缓存策略
目的:主要目的为了提高用户获取数据的速度。让响应更快.。缓存策略主要降低用户访问物理设备的频次。同时要求缓存中的数据就是数据库中的数据。
1.2、如何设计缓存
1.缓存的数据结构应该如何存储? 是否可以使用key-value结构
2.选用什么样的语言开发? C语言
3.应该考虑缓存大小是否有边界.如果有上限应该如何优化.
如何维护内存大小 LRU算法(最近最少使用.)(被动)
4.缓存的数据不可能永远保存到缓存中,应该为缓存数据设定时效性. (自动)
5.如果内存断电里边的数据都会丢失.。可以通过持久化(磁盘)策略保存缓存数据.
6.缓存事务问题 一个业务中可能多次操作缓存. 事务必须控制
2、Redis介绍
2.1、网址介绍
url:: http://www.redis.cn/
redis执行的速度:写操作 8.6万次/秒,读 11.2万次/秒 平均:10万次/秒 吞吐量
Redis在工作中一般当作缓存来使用。
3、Redis安装
3.1上传安装文件
3.2解压安装
1.解压redis
tar -zxvf redis-5.0.5.tar.gz
2.删除安装包
3.修改redis文件目录
mv redis-5.0.5 redis
3.3安装Redis
cd redis
make
make install
如果执行报错,说明缺少gcc等环境(gcc版本太低也会影响)。百度问题就可以解决了。
3.4修改redis配置文件
vim redis.conf
#显示行号
:set nu
1.关闭IP绑定(不关只能自己家访问)
#注释
2.关闭保护模式(yes改no)
3.开启后台启动(no是前台启动,占用终端)
4.保存退出
:wq
3.5Redis服务器操作命令
1.redis-server redis.conf 默认条件下 前台启动
2.redis-cli -p 6379 进入客户端 exit/quit/ctrl+c 退出客户端
3.redis-cli -p 6379 shutdown 或者 ps -ef |grep redis kill -9 PID号 关闭redis服务器.
4、Redis命令
4.1String 类型
命令 | 说明 | 案例 |
---|---|---|
set | 添加key-value | set username admin |
get | 根据key获取数据 | get username |
strlen | 根据key获取值的长度 | strlen key |
exists | 判断key是否存在 | exists name 返回1存在 0不存在 |
del | 删除redis中的key | del key |
Keys | 用于查询符合条件的key | keys * 查询redis中全部的key keys n?me 使用占位符获取数据 keys nam* 获取nam开头的数据 |
mset | 赋值多个key-value | mset key1 value1 key2 value2 key3 value3 |
mget | 获取多个key的值 | mget key1 key2 |
append | 对某个key的值进行追加 | append key value |
type | 检查某个key的类型 | type key |
select | 切换redis数据库 | select 0-15 redis中共有16个数据库 |
flushdb | 清空单个数据库 | flushdb |
flushall | 清空全部数据库 | flushall |
incr | 自动加1 | incr key |
decr | 自动减1 | decr key |
incrby | 指定数值添加 | incrby 10 |
decrby | 指定数值减 | decrby 10 |
expire | 指定key的生效时间 单位秒 | expire key 20 key20秒后失效 |
pexpire | 指定key的失效时间 单位毫秒 | pexpire key 2000 key 2000毫秒后失效 |
ttl | 检查key的剩余存活时间 | ttl key -2数据不存在 -1该数据永不超时 |
persist | 撤销key的失效时间 | persist key |
4.2Hash类型
命令 | 说明 | 案例 |
---|---|---|
hset | 为对象添加数据 | hset key field value |
hget | 获取对象的属性值 | hget key field |
hexists | 判断对象的属性是否存在 | HEXISTS key field 1表示存在 0表示不存在 |
hdel | 删除hash中的属性 | hdel user field [field …] |
hgetall | 获取hash全部元素和值 | HGETALL key |
hkyes | 获取hash中的所有字段 | HKEYS key |
hlen | 获取hash中所有属性的数量 | hlen key |
hmget | 获取hash里面指定字段的值 | hmget key field [field …] |
hmset | 为hash的多个字段设定值 | hmset key field value [field value …] |
hsetnx | 设置hash的一个字段,只有当这个字段不存在时有效 | HSETNX key field value |
hstrlen | 获取hash中指定key的值的长度 | HSTRLEN key field |
hvals | 获取hash的所有值 | HVALS user |
4.3List类型
说明:Redis中的List集合是双端循环列表,分别可以从左右两个方向插入数据.
List集合可以当做队列使用,也可以当做栈使用
队列:存入数据的方向和获取数据的方向相反
栈:存入数据的方向和获取数据的方向相同
命令 | 说明 | 案例 |
---|---|---|
lpush | 从队列的左边入队一个或多个元素 | LPUSH key value [value …] |
rpush | 从队列的右边入队一个或多个元素 | RPUSH key value [value …] |
lpop | 从队列的左端出队一个元素 | LPOP key |
rpop | 从队列的右端出队一个元素 | RPOP key |
lpushx | 当队列存在时从队列的左侧入队一个元素 | LPUSHX key value |
rpushx | 当队列存在时从队列的右侧入队一个元素 | RPUSHx key value |
lrange | 从列表中获取指定返回的元素 | LRANGE key start stop Lrange key 0 -1 获取全部队列的数据 |
lrem | 从存于 key 的列表里移除前 count 次出现的值为 value 的元素。 这个 count 参数通过下面几种方式影响这个操作: · count > 0: 从头往尾移除值为 value 的元素。 · count < 0: 从尾往头移除值为 value 的元素。 · count = 0: 移除所有值为 value 的元素。 | LREM list -2 “hello” 会从存于 list 的列表里移除最后两个出现的 “hello”。 需要注意的是,如果list里没有存在key就会被当作空list处理,所以当 key 不存在的时候,这个命令会返回 0。 |
Lset | 设置 index 位置的list元素的值为 value | LSET key index value |
4.4Set类型
4.5事务控制
说明:redis中操作可以添加事务的支持.一项任务可以由多个redis命令完成,如果有一个命令失败导致入库失败时.需要实现事务回滚.
命令 | 说明 | 案例 |
---|---|---|
multi | 标记一个事务开始 | 127.0.0.1:6379> MULTI OK |
exec | 执行所有multi之后发的命令 | 127.0.0.1:6379> EXEC OK |
discard | 丢弃所有multi之后发的命令 |
5、Redis入门案例
5.0添加jar包文件
<!--spring整合redis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
5.1操作String类型
public class TestRedis {
/**
* 测试String数据类型
* 1.链接redis服务器 192.168.126.129:6379
* 2.通过命令操作redis.
*
* 问题说明:程序链接不通 检查redis配置文件 是否修改3项.
* 修改之后重启redis服务器.
*/
private Jedis jedis;
@BeforeEach //当执行test测试方式时,首先执行该操作
public void init() {
//jedis对象实例化
jedis = new Jedis("192.168.126.129", 6379);
}
@Test
public void testString() {
//Jedis jedis = new Jedis("192.168.126.129", 6379);
//1.利用set方法实现redis赋值
jedis.set("jedis","天天都需要爱,心思由你猜!!!!!");
String value = jedis.get("jedis");
System.out.println(value);
//2.测试是否还有某个key
Boolean flag = jedis.exists("a");
System.out.println(flag);
//3.动态获取value的长度.
System.out.println(jedis.strlen("jedis"));
//4.动态获取所有key
Set<String> sets = jedis.keys("*");
System.out.println(sets);
}
/**
* 需求:
* 1.如果key存在则不允许修改数据.
*/
@Test
public void testString_NX() {
jedis.flushAll(); //清空redis
//测试1:
//jedis.set("a","100");
//jedis.set("a","1000"); redis对同样的数据进行操作时,其实做的是修改操作
//测试2:
//jedis.set("a", "100");
/*if(!jedis.exists("a")) {
jedis.set("a", "2000");
}*/
//测试3: jedis.setNX(); 只有数据不存在时,才能赋值成功!!
jedis.setnx("a","100"); //成功
jedis.setnx("a","1000"); //失败
System.out.println(jedis.get("a"));
}
/**
* 需求:赋值同时为数据添加超时时间
* @throws InterruptedException
* 说明:如果将赋值操作和超时的设定分开写,则丧失了操作的原子性.
* 原子性: 要求数据同时生效/同时不生效.
*/
@Test
public void testString_EX_PX() throws InterruptedException {
/*jedis.set("b", "100");
//int a = 1/0; //程序报错了.
jedis.expire("b", 10); //为key添加10秒超时时间
Thread.sleep(2000);
System.out.println("剩余超时时间:"+jedis.ttl("b")+"秒");*/
//ex方法时间单位 秒
jedis.setex("b", 10, "100"); //要么同时成功,要么同时失败
//赋值毫秒
jedis.psetex("c", 2000, "100");
}
/**
* 需求3:
* 1.要求赋值同时添加超时时间 操作满足原子性要求
* 2.如果key不存在时才能赋值.
* 目标: ex nx方法同时操作
*
* XX: 只有key存在时才会赋值.
* NX: 如果key不存在时才会赋值
* EX: 添加超时时间 单位秒
* PX: 添加超时时间单位毫秒
*/
@Test
public void testStringSet() {
SetParams setParams = new SetParams();
setParams.xx().ex(10);
jedis.set("c", "200", setParams);
jedis.set("c", "2000", setParams);
System.out.println(jedis.get("c"));
}
}
5.2操作Hash类型
//一般hash方式使用与业务数据的调用 {item: item详情 ,商品规格信息}
//如果业务数据需要嵌套可以采用hash方式进行存储.
@Test
public void testHash() {
Map<String,String> hashMap = new HashMap<String, String>();
hashMap.put("id", "101"); //更新操作
hashMap.put("name", "人类");
Long result = jedis.hset("person", hashMap);
System.out.println(result);
jedis.hset("dog", "id", "101");
jedis.hset("dog", "name", "jerry");
jedis.hset("dog", "age", "2");
System.out.println(jedis.hgetAll("dog"));
}
5.3操作List类型
/**
* 操作list集合
*
*/
@Test
public void testList() {
jedis.lpush("myList", "1","2","3","4");
String value = jedis.rpop("myList");
System.out.println(value);
}
5.4操作set类型
//简单的set集合 没有顺序
@Test
public void testSet(){
//1.向集合中添加数据
jedis.sadd("a", "1","2","3");
//2.获取集合中的数据
Set<String> sets = jedis.smembers("a");
System.out.println(sets);
//3.从集合中删除数据
jedis.srem("a", "1");
Set<String> sets2 = jedis.smembers("a");
System.out.println(sets2);
}
5.5事务控制
@Test
public void testTx() {
Transaction transaction = jedis.multi(); //开启事务
try {
transaction.set("a", "a");
transaction.set("b", "b");
int a = 1/0;
transaction.exec(); //事务提交
System.out.println("事务提交成功");
} catch (Exception e) {
e.printStackTrace();
transaction.discard(); //事务回滚
System.out.println("事务提交失败");
}
}