)
redis常用命令get/set/exists/del/keys/rename/dbsize/type/mget/mset/expire/setnx/incr/decr/append/flushallredis的数据类型String/Hash/List/Set/Zset/Hyperloglog/Geo/Stream/BitMapsMemcached和Redis的主要区别是什么Memcached:只能存储KV、没有持久化机制、不支持主从复制、是多线程的Redis:数据类型丰富、支持多种编程语言、功能丰富(持久化机制、内存淘汰策略、事务、发布订阅、pipeline、lua)、支持集群、分布式Hash与String的主要区别1.把所有相关的值聚集到一个key中,节省内存空间2.只使用一个key,减少key冲突3.当需要批量获取值的时候,只需要使用一个命令,减少内存/IO/CPU的消耗4.Hash不适合的场景:Field不能单独设置过期时间、需要考虑数据量分布的问题redis的Hash数据量大怎么取出就看你的数据量大小了,如果太大,却是不好遍历,如果有规则的key值的话,倒是可以利用分页的方式来处理,如果没有规律的话,只有用keys*来取了,或者是通过keysa*;keysz*;keys1*;keys0*等通配符的方式来顺序的读取,读取时要把内存分配的大一些,不然容易溢出。有3个通配符 *, ? ,[]二进制安全SDSC语言中,用“0”表示字符串的结束,如果字符串中本身就有“0”字符,那么这个字符串就会被截断,即非二进制安全;若通过某种机制,保证读写字符串时不损害其内容,则是二进制安全。redis3.2版本以前:struct sdshdr{ int len;//buf数组中已经使用的字节的数量,也就是SDS字符串长度 int free;//buf数组中未使用的字节的数量 char buf[];//字节数组,字符串就保存在这里面 };redis3.2版本后:struct_attribute_((_packed_))sdshdr8{ uint8_t len;//当前字节数组的长度 uint8_t alloc;//当前字节数组总共分配的内存大小 uimt8_t flag;//当前字节数组的属性,用来标识到底是sdshdr8还是sdshdr16等 char buf[]; //字符串真正的值 }SDS的特点1.不用担心内存溢出问题,如果需要会对SDS进行扩容。2.获取字符串长度时间复杂度为O(1),因为定义了len属性。3.通过‘空间预分配’和‘惰性空间释放’,防止多次重分配内存。4.判断是否结束的标志是len属性,可以包含‘\0’。redis事务redis的单个命令是原子性的(比如get/set/mget/mset),要么成功要么失败,不存在并发干扰的问题。如果涉及到多个命令的时候,需要把多个命令作为一个不可分割的处理序列,redis提供了事务的功能,可以把一组命令一起执行。事务特点:1.按进入队列的顺序执行2.不会受到其它客户端的请求的影响3.事务不能嵌套,多个multi命令效果一样事务用法:1.multi:开启事务2.exec:执行事务3.discard:取消事务4.watch:监视事务可能遇到的问题:1.在执行exec之前发生错误,队列都不会被执行。2.在执行exec之后发生的错误,只有错误的不会被执行。redis事务无法保证原子性和数据一致性。RESP通信协议RESP(Redis Serialization Protocol)序列化协议,容易实现、解析快、可读性强。就是把命令、长度和参数用\r\n连接起来。package redis; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class RespTest { private Socket socket; private OutputStream write; private InputStream read; public RespTest(String host, int port) throws IOException { socket = new Socket(host, port); write = socket.getOutputStream(); read = socket.getInputStream(); } /** * 实现了set方法 * @param key * @param val * @throws IOException */ public void set(String key, String val) throws IOException { StringBuffer sb = new StringBuffer(); // 代表3个参数(set key value) sb.append("*3").append("\r\n"); // 第一个参数(set)的长度 sb.append("$3").append("\r\n"); // 第一个参数的内容 sb.append("SET").append("\r\n"); // 第二个参数key的长度(不定,动态获取) sb.append("$").append(key.getBytes().length).append("\r\n"); // 第二个参数key的内容 sb.append(key).append("\r\n"); // 第三个参数value的长度(不定,动态获取) sb.append("$").append(val.getBytes().length).append("\r\n"); // 第三个参数value的内容 sb.append(val).append("\r\n"); // 发送命令 write.write(sb.toString().getBytes()); byte[] bytes = new byte[1024]; // 接收响应 read.read(bytes); System.out.println("-------------set-------------"); System.out.println(new String(bytes)); } /** * 实现了get方法 * @param key * @throws IOException */ public void get(String key) throws IOException { StringBuffer sb = new StringBuffer(); // 代表2个参数 sb.append("*2").append("\r\n"); // 第一个参数(get)的长度 sb.append("$3").append("\r\n"); // 第一个参数的内容 sb.append("GET").append("\r\n"); // 第二个参数key的长度 sb.append("$").append(key.getBytes().length).append("\r\n"); // 第二个参数内容 sb.append(key).append("\r\n"); write.write(sb.toString().getBytes()); byte[] bytes = new byte[1024]; read.read(bytes); System.out.println("-------------get-------------"); System.out.println(new String(bytes)); } public void passport(String password) throws IOException { StringBuffer sb = new StringBuffer(); // 代表2个参数 sb.append(