java redis常用命令_Redis的常用命令与Java整合及高级应用篇

一,redis是什么?

​首先数据库分为关系型数据库和非关系型数据库,关系型数据库是采用关系模型来组织数据的数据库,简单来说就是二维表格模型,同时保证事务的一致性。

​相反非关系型数据库采用key-value形式进行存储,是一种数据结构化存储方法的集合,具有分布式性质。

​Redis是当前比较热门的NOSQL系统之一,它是一个开源的使用ANSI c语言编写的key-value存储系统(区别于MySQL的二维表格的形式存储。)遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。

二,redis的优势

​1,性能快:redis读取的速度是110000次/s,写的速度是81000次/s。

​2,丰富的数据类型:string(字符串);list(列表);hash(哈希),set(集合);zset(有序集合)等。

​3,原子性:Redis的所有操作都是原子性的,且多个客户端同时访问redis客户端可获得更新后的值。

​4,持久化:集群(主从复制,分布式)。

三,redis与Memcached区别(经典面试题)

1 、redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储类型。memcache支持简单的数据类型,String,同时还可以缓存图片,视频。

2 、Redis支持数据的备份,即master-slave模式的数据备份(主从复制)。

3 、Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。

4、 redis的速度比memcached快很多

5、Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的IO复用模型。

6,数据安全性:memcache挂掉后,数据便消失;redis可以定期保存到磁盘(持久化)。

四,redis常用命令及springboot操作redis

4.1,引入依赖包。

org.springframework.boot

spring-boot-starter-data-redis

4.2,常用命令与代码整合操作。

​注意:redis默认使用JDK序列化方式

4.3,字符串操作类型。

/**

* String - 字符串类型的操作方式

* redisTemplate.opsForValue()

*/

@Test

public void stringType(){

//改为String序列化方式

redisTemplate.setKeySerializer(new StringRedisSerializer());

redisTemplate.setValueSerializer(new StringRedisSerializer());

//redis命令:set key value

redisTemplate.opsForValue().set("age", "19");

// redis命令:get key

String age = (String) redisTemplate.opsForValue().get("age");

System.out.println("-->" + age);

// redis命令:mset key value key value ...

Map map = new HashMap<>();

map.put("key1", "value1");

map.put("key2", "value2");

map.put("key3", "value3");

redisTemplate.opsForValue().multiSet(map);

// redis命令:mget key key key...

List keys = new ArrayList<>();

keys.add("key1");

keys.add("key2");

keys.add("key3");

List values = redisTemplate.opsForValue().multiGet(keys);

System.out.println("mget -->" + values);

// redis命令:del key

Boolean boo = redisTemplate.delete("key1");

// redis命令:strlen key - 可能会因为序列化的原因造成长度不准

Long resultLong = redisTemplate.opsForValue().size("age");

System.out.println("strlen --> " + resultLong);

// redis命令:getset key value

String oldValue = (String) redisTemplate.opsForValue().getAndSet("age", "25");

System.out.println("getset --> " + oldValue);

// redis命令:getrange key start end - 可能会因为序列化的原因造成长度不准

String age1 = redisTemplate.opsForValue().get("age", 0, 1);

System.out.println("getrange --> " + age1);

// redis命令:append - 可能会因为序列化的原因造成长度不准

Integer age2 = redisTemplate.opsForValue().append("age", "26");

System.out.println("append --> " + age2);

// redis命令:incr key - 自增 - 可能会因为序列化的原因造成长度不准

Long age3 = redisTemplate.opsForValue().increment("age", 10);

System.out.println("incr -->" + age3);

// redis命令:decr key - 自减

redisTemplate.opsForValue().increment("age", -10);

Long decr = redisTemplate.getConnectionFactory().getConnection().decr("age".getBytes());

System.out.println("decr --> " + decr);

}

4.4,Hash操作类型。

/**

* Hash数据类型的操作

*/

@Test

public void hashType(){

// redis命令:mset key field value

redisTemplate.opsForHash().put("person", "name", "张三");

redisTemplate.opsForHash().put("person", "age", 19);

// redis命令:mget key field

String value = (String) redisTemplate.opsForHash().get("person", "name");

System.out.println("mget-->" + value);

// redis命令:hmset key field1 value1 field2 value2 ...

Map map = new HashMap<>();

map.put("bookname", "Java精通之路");

map.put("price", "100.99");

redisTemplate.opsForHash().putAll("book", map);

// redis命令:hmget key field1 field2 ...

List list = new ArrayList<>();

list.add("bookname");

list.add("price");

List books = redisTemplate.opsForHash().multiGet("book", list);

System.out.println("hmget-->" + books);

// redis命令:del key

redisTemplate.delete("book");

// redis命令:hdel key field1 field2...

redisTemplate.opsForHash().delete("book", "bookname", "price");

// redis命令:hexists key field

Boolean bool = redisTemplate.opsForHash().hasKey("book", "bookname");

System.out.println("hexists-->" + bool);

// redis命令:hlen key

Long length = redisTemplate.opsForHash().size("book");

System.out.println("hlen-->" + length);

// redis命令:hkeys key - 展示key对应的所有字段名称

Set set = redisTemplate.opsForHash().keys("book");

System.out.println("hkeys-->" + set);

// redis命令:hvals key - 展示key对应的所有字段的值

List values = redisTemplate.opsForHash().values("book");

System.out.println("hvals-->" + values);

// redis命令:hgetall key - field and value

Map bookmap = redisTemplate.opsForHash().entries("book");

System.out.println("hgetall-->" + bookmap);

}

4.5,链表数据结构。

/**

* 链表数据结构

*/

@Test

public void linkedType(){

// redis命令:lpush key value1 value2...

redisTemplate.opsForList().leftPush("book", "c++");

redisTemplate.opsForList().leftPushAll("book", "c", "java");

// redis命令:rpush key value1 value2

redisTemplate.opsForList().rightPush("book", "mysql");

redisTemplate.opsForList().rightPushAll("book", "oracle", "sqlserver");

// redis命令:lindex key index

String book0 = (String) redisTemplate.opsForList().index("book", 0);

System.out.println("lindex-->" + book0);

// redis命令:llen key

Long bookLen = redisTemplate.opsForList().size("book");

System.out.println("llen-->" + bookLen);

// redis命令:lpop key

String leftBook = (String) redisTemplate.opsForList().leftPop("book");

System.out.println("lpop-->" + leftBook);

// redis命令:rpop key

String rightBook = (String) redisTemplate.opsForList().rightPop("book");

System.out.println("rpop-->" + rightBook);

// redis命令:linsert key before|after oldnode newnode

redisTemplate.opsForList().leftPush("book", "java", "pythod");

redisTemplate.opsForList().rightPush("book", "java", "jquery");

// redis命令:lrange key start end

List rangeList = redisTemplate.opsForList().range("book", 0, redisTemplate.opsForList().size("book") - 1);

System.out.println("lrange-->" + rangeList);

// redis命令:lset key index value

redisTemplate.opsForList().set("book", 0, "db");

// redis命令:ltrim key start end

redisTemplate.opsForList().trim("book", 1, 3);

// redis命令:lrange key start end

List rangeList2 = redisTemplate.opsForList().range("book", 0, redisTemplate.opsForList().size("book") - 1);

System.out.println("lrange-->" + rangeList2);

}

4.6,集合操作类型。

/**

* 集合操作

*/

@Test

public void setType(){

// redis命令:sadd

redisTemplate.opsForSet().add("person", "小明","小红","小刚");

// redis命令:scard

Long person = redisTemplate.opsForSet().size("person");

System.out.println("scard-->" + person);

// redis命令:smembers

Set set = redisTemplate.opsForSet().members("person");

System.out.println("smembers-->" + set);

}

4.7,有序集合操作类型

/**

* 有序集合

*/

@Test

public void zsetType(){

redisTemplate.opsForZSet().add("book", "mysql", 1.5);

redisTemplate.opsForZSet().add("book", "java", 8.5);

redisTemplate.opsForZSet().add("book", "html", 10.5);

Set set = redisTemplate.opsForZSet().range("book", 0, redisTemplate.opsForZSet().size("book") - 1);

System.out.println(set);

}

五,redis高级应用

5.1,事务

​与其他NoSQL不同,Redis是存在事务的,尽管没有数据库那么强大,但是还是非常有用,尤其是在高并发的情况中,使用redis的事务可以保证数据一致性的同时,大幅度提高数据读写的响应速度。

​redis的事务是使用multi-exec的命令组合,使用它可以提供两个重要保证:

​1、事务是一个被隔离的操作,事务中的方法都会被redis进行序列化并按顺序执行,事务在执行的过程中不会被其他客户端的发出的命令所打断。

​2、事务是一个原子性操作,它要么全部执行、要么全部不执行。

​事务的常用命令:

​multi:开启事务,之后的命令就会进入队列,而不是马上执行。

​watch key1 [key2]...:监听某些键,当被监听的键在提交事务前被修改,则事务会回滚 (基于乐观锁机制)。

​unwatch key1 [key2]...:取消监听。

​exec:执行事务,如果被监听的键没有被修改,则采用提交命令,否则就执行回滚命令。

​discard:回滚事务。

​事务的开启及提交如下图:

dcb0fc7da1f1d9687366103bbcc57aad.png

​从上图中看出,当开始事务时进行操作,命令并不会马上执行,而是放在队列中,只有在事务提交后才会执行。

​但是,要注意注意:redis中,如果遇到格式正确而数据类型不符合的情况时,不会进行事务回滚。这是什么意思,如下图操作所示:

2c6023addada844e65b505921824d576.png

​问题描述:比如我要保存1000金额到内存中,但是我不小心将金额输入成1000a,后面多了一个a。但是同样保存到了队列中。最后当提交事务的时候便会报错,可是1000a还是保存到了内存,证明事务并没有回滚。

​redis中存在监听机制,可以监听某一个key。

f88ab516f02ae1efd1de0c19ba381235.png

/**

* redis的事务管理,要保证事务的开启和提交是同一条连接。

*/

@Test

public void transcation(){

List results = (List) redisTemplate.execute(new SessionCallback() {

@Override

public Object execute(RedisOperations redisOperations) throws DataAccessException {

//开启事务

redisOperations.multi();

//进行操作

redisOperations.opsForValue().set("name", "张三");

redisOperations.opsForValue().get("name");

//提交事务

List result = redisOperations.exec();

return result;

}

});

System.out.println("-->" + results);

}

5.2,流水线

​在现实情况中,redis的读写速度十分快,而系统的瓶颈往往是在网络通信中的延迟。redis可能会再很多时候处于空闲状态而等待命令的到达。为了解决这个问题,可以使用redis的流水线,流水线是一种通讯协议,类似一个队列批量执行一组命令。

​由于这种情况在实际工作中较少使用,所以就简短介绍一下。

/**

* 流水线

*/

@Test

public void pipelined(){

//流水线

long begin = System.currentTimeMillis();

redisTemplate.executePipelined(new SessionCallback() {

@Override

public Object execute(RedisOperations redisOperations) throws DataAccessException {

for (int i = 0; i < 100000; i++) {

redisOperations.opsForValue().set("key" + i, "value" + i);

redisOperations.opsForValue().get("key" + i);

}

return null;

}

});

long end = System.currentTimeMillis();

System.out.println("耗时:" + (end - begin));

}

5.3,发布订阅

​说到发布订阅是否会想到RabbitMQ等消息中间件?

​但是redis的发布订阅具有实时性,当发布者改变数据时,订阅者便会接收到更改后的消息。

​使用命令:

​subscribe chat:订阅chat渠道。

​publish chat "message:发布消息到chat渠道。

5.3.1,定义监听类:

/**

* Redis消息监听器

*/

public class RedisMessageListener implements MessageListener{

private RedisTemplate template;

@Override

public void onMessage(Message message, byte[] pattern) {

//获取渠道名称

System.out.println("渠道名称:" + new String(pattern));

//获得消息

byte[] body = message.getBody();

//获得值序列化转换器

String msg = (String) template.getValueSerializer().deserialize(body);

System.out.println("消息为:" + msg);

}

public RedisTemplate getTemplate() {

return template;

}

public void setTemplate(RedisTemplate template) {

this.template = template;

}

}

5.3.2,配置文件配置监听

5.3.3,发布消息

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-*.xml");

RedisTemplate redistemp = context.getBean(RedisTemplate.class);

redistemp.convertAndSend("yx", "Hello");

5.4,超时时间

​在redis中的超时时间时非常重要的,因为我们的内存时有限的,在一段时间内如果没有对一些数据进行处理。那便会产生很多的垃圾数据,因此对数据进行时间 上的设置是一种较好的习惯。

​这里先暂时不讲述过期时间的原理,后面会与大家分享,还请关注哦~~~

​超时时间的命令:

​persist key:持久化key,即得永生(移除key的超时时间)。

​expire key seconds:设置超时时间,单位为秒。

​ttl key:查看key的超时时间,单位为秒,返回-1表示没有超时时间,如果key不存在或者已经超时,则返回-2。

​pttl key:查看key的超时时间,单位为毫秒。

​pexpire key milliseconds:设置key的超时时间,以毫秒为单位。

​关于超时时间需要有几点注意:当一个key过了超时时间以后,并不会立刻从内存中移除。在以下情况下数据会被清除。

​1、当要获得key的值的时候,比如执行了get key命令。

​2、系统自己会有一个定时器,每隔1秒,扫描一次内存。清除超时的key(不会完全扫描所有的key,不会完全的移除所有超时的key)。

​3、内存已满,就会根据配置文件进行内存数据的清理。

@Test

public void expire() throws ParseException {

redisTemplate.opsForValue().set("name", "小明");

//设置超时时间 - 5 ~ 10分钟

redisTemplate.expire("name", 10, TimeUnit.SECONDS);

//设置超时时间到指定的时间

String time = "2019-08-23 12:00:00";

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

Date date = sdf.parse(time);

redisTemplate.expireAt("name", date);

//移除超时时间

redisTemplate.persist("name");

//获得还能活多久

redisTemplate.getExpire("name");

String name = (String) redisTemplate.opsForValue().get("name");

System.out.println(name);

try {

Thread.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(name);

}

六,总结

​写到这里redis的基本使用也差不多了,但是仍有很多技术点没有记录到。比如与Lua语言的结合使用,redis的持久化,内存的淘汰策略,读写分离(哨兵模式),集群等。

​如果你看到这篇博客,以上没有分享的内容会在后续发布的,还请关注~

​最后,以上内容均是自主学习的总结,如有错误或者不合适的地方欢迎留言(或者邮箱)指教。

​感谢观看!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值