From 8716dd86486a1346270da603a81bce551f5d27e4 Mon Sep 17 00:00:00 2001 From: luoxiang <2806718453@qq.com> Date: Sat, 5 Jan 2019 11:46:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0redis=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pictures/redis官方推荐客户端.png | Bin 0 -> 40388 bytes .../spring+redis+ano项目目录结构.png | Bin 0 -> 18223 bytes pictures/spring+redis项目目录结构.png | Bin 0 -> 24816 bytes spring/spring-druid-mybatis/README.md | 16 +- spring/spring-redis-annotation/README.md | 530 +++++++++++++++++ .../config/jedis/SingleJedisConfig.java | 1 - .../src/main/resources/jedis.properties | 3 + .../heibaiying/redisson/RedissonSamples.java | 2 +- spring/spring-redis/README.md | 553 ++++++++++++++++++ .../src/main/resources/jedis/jedis.properties | 3 + .../src/main/resources/jedis/jedis.xml | 4 +- .../src/main/resources/redisson/redisson.xml | 4 +- 12 files changed, 1095 insertions(+), 21 deletions(-) create mode 100644 pictures/redis官方推荐客户端.png create mode 100644 pictures/spring+redis+ano项目目录结构.png create mode 100644 pictures/spring+redis项目目录结构.png create mode 100644 spring/spring-redis-annotation/README.md create mode 100644 spring/spring-redis/README.md diff --git a/pictures/redis官方推荐客户端.png b/pictures/redis官方推荐客户端.png new file mode 100644 index 0000000000000000000000000000000000000000..402586c5c06aebb0105f61da96ede41698edcf45 GIT binary patch literal 40388 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 a`+h|0C|6P>@c!tL{C3O45>#pI8uf31V?nb3 literal 0 HcmV?d00001 diff --git a/pictures/spring+redis+ano项目目录结构.png b/pictures/spring+redis+ano项目目录结构.png new file mode 100644 index 0000000000000000000000000000000000000000..fc3b7fe15734e69ae438bcdd856eb3e01ba1c27d GIT binary patch literal 18223 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%0A%rpDQ<3! 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 literal 0 HcmV?d00001 diff --git a/spring/spring-druid-mybatis/README.md b/spring/spring-druid-mybatis/README.md index 7523a69..a7a243b 100644 --- a/spring/spring-druid-mybatis/README.md +++ b/spring/spring-druid-mybatis/README.md @@ -106,8 +106,6 @@ ``` -
- #### 2、在web.xml 进行如下配置 ```xml @@ -177,8 +175,6 @@ ``` -
- #### 3、在resources文件夹下新建数据库配置文件jdbc.properties ```properties @@ -193,8 +189,6 @@ oracle.username=用户名 oracle.password=密码 ``` -
- #### 4、在resources文件夹下创建springApplication.xml 配置文件和druid.xml配置文件 ```xml @@ -260,7 +254,7 @@ oracle.password=密码 - + @@ -308,8 +302,6 @@ oracle.password=密码 ``` -
- #### 5、新建mybtais 配置文件 更多settings配置项可以参考[官方文档](http://www.mybatis.org/mybatis-3/zh/configuration.html) ```xml @@ -333,8 +325,6 @@ oracle.password=密码 ``` -
- #### 6、新建查询接口及其对应的mapper文件 ```java @@ -382,8 +372,6 @@ public interface OracleDao { ``` -
- #### 7.新建测试controller进行测试 ```java @@ -445,8 +433,6 @@ public class OracleController { ``` -
- #### 8、druid 监控页面访问地址http://localhost:8080/druid/index.html ![druid控制台](https://github.com/heibaiying/spring-samples-for-all/blob/master/pictures/druid%E6%8E%A7%E5%88%B6%E5%8F%B0.png) diff --git a/spring/spring-redis-annotation/README.md b/spring/spring-redis-annotation/README.md new file mode 100644 index 0000000..c821b72 --- /dev/null +++ b/spring/spring-redis-annotation/README.md @@ -0,0 +1,530 @@ +# spring 整合 redis (注解方式) + +## 一、说明 + +### 1.1 Redis 客户端说明 + +关于spring 整合 mybatis 本用例提供两种整合方法: + +1. jedis: 官方推荐的java客户端,能够胜任redis的大多数基本使用; +2. redisson:也是官方推荐的客户端,比起jedis提供了更多高级的功能,比如分布式锁、集合数据切片等功能。同时提供了丰富而全面的中英文版本的wiki。 + +注:关于redis其他语言官方推荐的客户端可以在[客户端](http://www.redis.cn/clients.html)该网页查看,其中官方推荐的用了黄色星星:star:标注。 + +![redis官方推荐客户端](D:\spring-samples-for-all\pictures\redis官方推荐客户端.png) + + + +### 1.2 Redis可视化软件 + +推荐**Redis Desktop Manager** 作为可视化查看工具,可以直观看到用例中测试关于存储实体对象序列化的情况。 + +### 1.3 项目结构说明 + +1. jedis和redisson的配置类和单元测试分别位于config和test下对应的包中,其中集群的配置类以cluster开头。 +2. 实体类Programmer.java用于测试Redisson序列化与反序列化 + +![spring+redis+ano项目目录结构](D:\spring-samples-for-all\pictures\spring+redis+ano项目目录结构.png) + + + +### 1.3 依赖说明 + +除了spring的基本依赖外,需要导入jedis 和 redisson 对应的客户端依赖包 + +```xml + + redis.clients + jedis + 3.0.0 + + + org.redisson + redisson + 3.9.1 + + + + io.netty + netty-all + 4.1.32.Final + +``` + + + +## 二、spring 整合 jedis + +#### 2.1 新建基本配置文件和其映射类 + +```properties +redis.host=127.0.0.1 +redis.port=6379 +# 连接超时时间 +redis.timeout=2000 +# 最大空闲连接数 +redis.maxIdle=8 +# 最大连接数 +redis.maxTotal=16 +``` + +```java +@Configuration +@PropertySource(value = "classpath:jedis.properties") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class RedisProperty { + + @Value("${redis.host}") + private String host; + @Value("${redis.port}") + private int port; + @Value("${redis.timeout}") + private int timeout; + @Value("${redis.maxIdle}") + private int maxIdle; + @Value("${redis.maxTotal}") + private int maxTotal; +} +``` + + + +#### 2.2 单机配置 + +```java +/** + * @author : heibaiying + * @description : Jedis 单机配置 + */ +@Configuration +@ComponentScan(value = "com.heibaiying.*") +public class SingleJedisConfig { + + @Bean + public JedisPool jedisPool(RedisProperty property) { + JedisPoolConfig poolConfig = new JedisPoolConfig(); + poolConfig.setMaxIdle(property.getMaxIdle()); + poolConfig.setMaxTotal(property.getMaxTotal()); + return new JedisPool(poolConfig, property.getHost(), property.getPort(), property.getTimeout()); + } + + @Bean(destroyMethod = "close") + public Jedis jedis(JedisPool jedisPool) { + return jedisPool.getResource(); + } +} +``` + +#### 2.3 集群配置 + +```java +@Configuration +@ComponentScan(value = "com.heibaiying.*") +public class ClusterJedisConfig { + + @Bean + public JedisCluster jedisCluster(RedisProperty property) { + JedisPoolConfig poolConfig = new JedisPoolConfig(); + poolConfig.setMaxIdle(property.getMaxIdle()); + poolConfig.setMaxTotal(property.getMaxTotal()); + Set nodes = new HashSet(); + nodes.add(new HostAndPort("127.0.0.1", 6379)); + nodes.add(new HostAndPort("127.0.0.1", 6380)); + return new JedisCluster(nodes, 2000); + } +} +``` + +#### 2.4 单机版本测试用例 + +1.需要注意的是,对于jedis而言,单机版本和集群版本注入的实例是不同的; + +2.jedis本身并不支持序列化于反序列化操作,如果需要存储实体类,需要序列化后存入。(redisson本身就支持序列化于反序列化,详见下文) + +```java +/** + * @author : heibaiying + * @description :redis 单机版测试 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = SingleJedisConfig.class) +public class JedisSamples { + + @Autowired + private Jedis jedis; + + @Test + public void Set() { + jedis.set("hello", "spring annotation"); + } + + @Test + public void Get() { + String s = jedis.get("hello"); + System.out.println(s); + } + + @Test + public void setEx() { + String s = jedis.setex("spring", 10, "我会在10秒后过期"); + System.out.println(s); + } + +} +``` + +#### 2.5 集群版本测试用例 + +```java +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = ClusterJedisConfig.class) +public class JedisClusterSamples { + + @Autowired + private JedisCluster jedisCluster; + + @Test + public void Set() { + jedisCluster.set("hello", "spring"); + } + + @Test + public void Get() { + String s = jedisCluster.get("hello"); + System.out.println(s); + } + + @Test + public void setEx() { + String s = jedisCluster.setex("spring", 10, "我会在10秒后过期"); + System.out.println(s); + } + + +} +``` + + + +## 三、spring 整合 redisson + +#### 2.1 单机配置 + +```java +/** + * @author : heibaiying + * @description : redisson 单机配置 + */ +@Configuration +public class SingalRedissonConfig { + + @Bean + public RedissonClient redissonClient() { + Config config = new Config(); + config.setTransportMode(TransportMode.NIO); + config.useSingleServer().setAddress("redis://127.0.0.1:6379"); + return Redisson.create(config); + } + +} +``` + +#### 2.2 集群配置 + +```java +/** + * @author : heibaiying + * @description : redisson 集群配置 + */ +@Configuration +public class ClusterRedissonConfig { + + //@Bean + public RedissonClient redissonClient() { + Config config = new Config(); + config.useClusterServers() + .setScanInterval(2000) // 集群状态扫描间隔时间,单位是毫秒 + //可以用"rediss://"来启用SSL连接 + .addNodeAddress("redis://127.0.0.1:6379", "redis://127.0.0.1:6380") + .addNodeAddress("redis://127.0.0.1:6381"); + return Redisson.create(config); + } + +} +``` + +#### 2.3 存储基本类型测试用例 + +1. 这里需要注意的是,对于Redisson而言, 单机和集群最后在使用的时候注入的都是RedissonClient,这和jedis是不同的。 + +```java +/** + * @author : heibaiying + * @description :redisson 操作普通数据类型 + */ + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = SingalRedissonConfig.class) +public class RedissonSamples { + + @Autowired + private RedissonClient redissonClient; + + @Test + public void Set() { + // key 存在则更新 不存在则删除 + RBucket rBucket = redissonClient.getBucket("redisson"); + rBucket.set("annotation Value"); + redissonClient.shutdown(); + } + + @Test + public void Get() { + // key 存在则更新 不存在则删除 + RBucket rBucket = redissonClient.getBucket("redisson"); + System.out.println(rBucket.get()); + } + + @Test + public void SetEx() { + // key 存在则更新 不存在则删除 + RBucket rBucket = redissonClient.getBucket("redissonEx"); + rBucket.set("我在十秒后会消失", 10, TimeUnit.SECONDS); + } + + + @After + public void close() { + redissonClient.shutdown(); + } +} + +``` + +#### 2.4 存储实体对象测试用例 + +```java +/** + * @author : heibaiying + * @description :redisson 对象序列化与反序列化 + */ + + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = SingalRedissonConfig.class) +public class RedissonObjectSamples { + + @Autowired + private RedissonClient redissonClient; + + // Redisson的对象编码类是用于将对象进行序列化和反序列化 默认采用Jackson + + @Test + public void Set() { + RBucket rBucket = redissonClient.getBucket("programmer"); + rBucket.set(new Programmer("xiaoming", 12, 5000.21f, new Date())); + redissonClient.shutdown(); + //存储结果: {"@class":"com.heibaiying.com.heibaiying.bean.Programmer","age":12,"birthday":["java.util.Date",1545714986590],"name":"xiaoming","salary":5000.21} + } + + @Test + public void Get() { + RBucket rBucket = redissonClient.getBucket("programmer"); + System.out.println(rBucket.get()); + } + + @After + public void close() { + redissonClient.shutdown(); + } +} +``` + +## 附:Redis的数据结构和操作命令 + +### 1.1 预备 + +#### 1.1.1 全局命令 + +1. 查看所有键: **keys \*** + +2. 查看键总数:**dbsize** + +3. 检查键是否存在:**exists key** + +4. 删除键:**del key [key ...]** 支持删除多个键 + +5. 键过期:**expire key seconds** + + ttl命令会返回键的剩余过期时间, 它有3种返回值: + + - 大于等于0的整数: 键剩余的过期时间。 + - -1: 键没设置过期时间。 + - -2: 键不存在 + +6. 键的数据结构 **type key** + +#### 1.1.2 数据结构和内部编码 + +type命令实际返回的就是当前键的数据结构类型, 它们分别是:**string**(字符串) 、 **hash**(哈希) 、 **list**(列表) 、 **set**(集合) 、 **zset**(有序集合) + +#### 1.1.3 单线程架构 + +1. 纯内存访问, Redis将所有数据放在内存中, 内存的响应时长大约为100纳秒, 这是Redis达到每秒万级别访问的重要基础。 +2. 非阻塞I/O, Redis使用epoll作为I/O多路复用技术的实现, 再加上Redis自身的事件处理模型将epoll中的连接、 读写、 关闭都转换为事件, 不在网络I/O上浪费过多的时间, 如图2-6所示。 +3. 单线程避免了线程切换和竞态产生的消耗。 + +### 1.2 字符串 + +| 作用 | 格式 | 参数或示例 | +| ---------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 设置值 | set key value \[ex seconds]\[px milliseconds][nx\|xx] setnx setex | ex seconds: 为键设置秒级过期时间。
px milliseconds: 为键设置毫秒级过期时间。
nx: 键必须不存在, 才可以设置成功, 用于添加。
xx: 与nx相反, 键必须存在, 才可以设置成功, 用于更新。 | +| 获取值 | get key | r如果获取的键不存在 ,则返回nil(空) | +| 批量设置 | mset key value [key value ...] | mset a 1 b 2 c 3 d 4 | +| 批量获取值 | mget key [key ...] | mget a b c d | +| 计数 | incr key decr key incrby key increment(指定数值自增)
decrby key decrement(指定数值自减)
incrbyfloat key increment (浮点数自增) | 值不是整数, 返回错误。 值是整数, 返回自增或自减后的结果。
键不存在,创建键,并按照值为0自增或自减, 返回结果为1。 | +| 追加值 | append key value | 向字符串的默认追加值 | +| 字符串长度 | strlen key | 获取字符串长度,中文占用三个字节 | +| 设置并返回原值 | getset key value | | +| 设置指定位置的租字符串 | setrange key offeset value | | +| 获取部分字符串 | getrange key start end | | + +### 1.3 哈希 + +| 作用 | 格式 | 参数或示例 | +| ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 设置值 | hset key field value | hset user:1 name tom
hset user:1 age 12 | +| 获取值 | hget key field | hget user:1 name | +| 删除field | hdel key field [field ...] | | +| 计算field个数 | hlen key | | +| 批量设置或获取field-value | hmget key field [field]
hmset key field value [field value...] | hmset user:1 name mike age 12 city tianjin
hmget user:1 name city | +| 判断field是否存在 | hexists key field | | +| 获取所有field | hkeys key | | +| 获取所有value | hvals key | | +| 获取所有的filed-value | hgetall key | 如果哈希元素个数比较多, 会存在阻塞Redis的可能。
获取全部 可以使用hscan命令, 该命令会渐进式遍历哈希类型 | +| 计数 | hincrby key field
hincrbyfloat key field | | + +### 1.4 列表 + +| 作用 | 格式 | 参数或示例 | +| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 增 | 左侧插入:lpush key value [value ...] 右侧插入:rpush key value [value ...] 某个指定元素前后插入:linsert key before\|after pivot value | | +| 查 | 获取指定范围内的元素列表:lrange key start end 获取列表指定索引下标的元素:lindex key index 获取列表指定长度:llen key | lrange listkey 0 -1 | +| 删 | 从列表左侧弹出元素:lpop key 从列表右侧弹出元素:rpop key 删除指定元素:lrem key count value 截取列表:ltrim key start end | count>0, 从左到右, 删除最多count个元素。
count<0, 从右到左, 删除最多count绝对值个元素。
count=0, 删除所有 | +| 改 | 修改指定索引下标的元素:lset key index newValue | | +| 阻塞操作 | blpop key [key ...] timeout brpop key [key ...] timeout | key[key...]: 多个列表的键。 timeout: 阻塞时间\|等待时间(单位: 秒) | + + + +### 1.5 集合 + +集合(set) 类型也是用来保存多个的字符串元素, 但和列表类型不一样的是, **集合中不允许有重复元素**, 并且集合中的元素是无序的, **不能通过索引下标获取元素**。 + +**集合内操作**: + +| 作用 | 格式 | 参数或示例 | +| -------------------- | ------------------------------ | ----------------------------------------- | +| 添加元素 | sadd key element [element ...] | 返回结果为添加成功的元素个数 | +| 删除元素 | srem key element [element ...] | 返回结果为成功删除的元素个数 | +| 计算元素个数 | scard key | | +| 判断元素是否在集合中 | sismember key element | | +| 随机返回 | srandmember key [count] | 随机从集合返回指定个数元素,count 默认为1 | +| 从集合随机弹出元素 | spop key | srandmember 不会从集合中删除元素,spop 会 | +| 获取集合中所有元素 | smembers key | 可用sscan 代替 | + +**集合间操作**: + +| 作用 | 格式 | +| ---------------------------- | ------------------------------------------------------------ | +| 求多个集合的交集 | sinter key [key ...] | +| 求多个集合的并集 | suinon key [key ...] | +| 求多个集合的差集 | sdiff key [key ...] | +| 将交集、并集、差集的结果保存 | sinterstore destination key [key ...]
suionstore destination key [key ...]
sdiffstore destination key [key ...] | + +### 1.6 有序集合 + +有序集合中的元素可以排序。 但是它和列表使用索引下标作为排序依据不同的是, 它给每个元素设置一个分数(score) 作为排序的依据。 + +**集合内操作**: + +| 作用 | 格式 | 参数或示例 | +| ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 添加成员 | zadd key score member [score member ...] | nx: member必须不存在, 才可设置成功, 用于添加。
xx: member必须存在, 才可以设置成功, 用于更新。
ch: 返回此次操作后, 有序集合元素和分数发生变化的个数
incr: 对score做增加, 相当于后面介绍的zincrby。 | +| 计算成员个数 | zcard key | | +| 计算某个成员的分数 | zscore key member | | +| 计算某个成员的排名 | zrank key member zrevrank key member | zrank是从分数从低到高返回排名, zrevrank反之。 | +| 删除成员 | zrem key member [member ...] | | +| 增加成员分数 | zincrby key increment member | zincrby user:ranking 9 tom | +| 返回指定排名范围的成员 | zrange key start end [withscores] zrange key start end [withscores] | zrange是从低到高返回, zrevrange反之。 | +| 返回指定分数范围内的成员 | zrangebyscore key min max \[withscores][limit offset count] zrevrangebyscore key max min \[withscores][limit offset count] | 其中zrangebyscore按照分数从低到高返回, zrevrangebyscore反之。 [limit offset count]选项可以限制输出的起始位置和个数: 同时min和max还支持开区间(小括号) 和闭区间(中括号) , -inf和+inf分别代表无限小和无限大 | +| 删除指定排名内的升序元素 | zremrangerank key start end | | +| 删除指定分数范围的成员 | zremrangebyscore key min max | | + +**集合间操作**: + +| 作用 | 格式 | +| ---- | ------------------------------------------------------------ | +| 交集 | zinterstore destination numkeys key \[key ...] [weights weight [weight ...]] \[aggregate sum\|min\|max] | +| 并集 | zunionstore destination numkeys key \[key ...] [weights weight [weight ...]] \[aggregate sum\|min\|max] | + +- destination: 交集计算结果保存到这个键。 +- numkeys: 需要做交集计算键的个数。 +- key[key...]: 需要做交集计算的键。 +- weights weight[weight...]: 每个键的权重, 在做交集计算时, 每个键中的每个member会将自己分数乘以这个权重, 每个键的权重默认是1。 +- aggregate sum|min|max: 计算成员交集后, 分值可以按照sum(和) 、min(最小值) 、 max(最大值) 做汇总, 默认值是sum。 + +### 1.7 键管理 + +#### 1.7.1 单个键管理 + +##### 1.键重命名 + +**rename key newkey** + + 为了防止被强行rename, Redis提供了renamenx命令, 确保只有newKey不存在时候才被覆盖。 + +##### 2. 随机返回键 + + **random key** + +##### 3.键过期 + +- expire key seconds: 键在seconds秒后过期。 +- expireat key timestamp: 键在秒级时间戳timestamp后过期。 +- pexpire key milliseconds: 键在milliseconds毫秒后过期。 +- pexpireat key milliseconds-timestamp键在毫秒级时间戳timestamp后过期 + +注意: + +1. 如果expire key的键不存在, 返回结果为0 +2. 如果设置过期时间为负值, 键会立即被删除, 犹如使用del命令一样 +3. persist key t命令可以将键的过期时间清除 +4. 对于字符串类型键, 执行set命令会去掉过期时间, 这个问题很容易在开发中被忽视 +5. Redis不支持二级数据结构(例如哈希、 列表) 内部元素的过期功能, 例如不能对列表类型的一个元素做过期时间设置 +6. setex命令作为set+expire的组合, 不但是原子执行, 同时减少了一次网络通讯的时间 + +#### 1.7.2 键遍历 + +##### 1. 全量键遍历 + +**keys pattern** + +##### 2. 渐进式遍历 + +scan cursor \[match pattern] \[count number] + +- cursor是必需参数, 实际上cursor是一个游标, 第一次遍历从0开始, 每次scan遍历完都会返回当前游标的值, 直到游标值为0, 表示遍历结束。 +- match pattern是可选参数, 它的作用的是做模式的匹配, 这点和keys的模式匹配很像。 +- count number是可选参数, 它的作用是表明每次要遍历的键个数, 默认值是10, 此参数可以适当增大。 + +#### 1.7.3 数据库管理 + +##### 1.切换数据库 + +**select dbIndex** + +##### 2.flushdb/flushall + +flushdb/flushall命令用于清除数据库, 两者的区别的是flushdb只清除当前数据库, flushall会清除所有数据库。 \ No newline at end of file diff --git a/spring/spring-redis-annotation/src/main/java/com/heibaiying/config/jedis/SingleJedisConfig.java b/spring/spring-redis-annotation/src/main/java/com/heibaiying/config/jedis/SingleJedisConfig.java index 7d43af4..f38d5ac 100644 --- a/spring/spring-redis-annotation/src/main/java/com/heibaiying/config/jedis/SingleJedisConfig.java +++ b/spring/spring-redis-annotation/src/main/java/com/heibaiying/config/jedis/SingleJedisConfig.java @@ -28,7 +28,6 @@ public class SingleJedisConfig { } @Bean(destroyMethod = "close") - @Scope(value = SCOPE_PROTOTYPE) public Jedis jedis(JedisPool jedisPool) { return jedisPool.getResource(); } diff --git a/spring/spring-redis-annotation/src/main/resources/jedis.properties b/spring/spring-redis-annotation/src/main/resources/jedis.properties index f25cf51..1a0357d 100644 --- a/spring/spring-redis-annotation/src/main/resources/jedis.properties +++ b/spring/spring-redis-annotation/src/main/resources/jedis.properties @@ -1,5 +1,8 @@ redis.host=127.0.0.1 redis.port=6379 +# ӳʱʱ redis.timeout=2000 +# redis.maxIdle=8 +# redis.maxTotal=16 \ No newline at end of file diff --git a/spring/spring-redis-annotation/src/test/java/heibaiying/redisson/RedissonSamples.java b/spring/spring-redis-annotation/src/test/java/heibaiying/redisson/RedissonSamples.java index 20e7197..7528a18 100644 --- a/spring/spring-redis-annotation/src/test/java/heibaiying/redisson/RedissonSamples.java +++ b/spring/spring-redis-annotation/src/test/java/heibaiying/redisson/RedissonSamples.java @@ -14,7 +14,7 @@ import java.util.concurrent.TimeUnit; /** * @author : heibaiying - * @description :redisson 操作普通对象 + * @description :redisson 操作普通数据类型 */ diff --git a/spring/spring-redis/README.md b/spring/spring-redis/README.md new file mode 100644 index 0000000..c2c8964 --- /dev/null +++ b/spring/spring-redis/README.md @@ -0,0 +1,553 @@ +# spring 整合 redis (xml配置方式) + +## 一、说明 + +### 1.1 Redis 客户端说明 + +关于spring 整合 mybatis 本用例提供两种整合方法: + +1. jedis: 官方推荐的java客户端,能够胜任redis的大多数基本使用; +2. redisson:也是官方推荐的客户端,比起jedis提供了更多高级的功能,比如分布式锁、集合数据切片等功能。同时提供了丰富而全面的中英文版本的wiki。 + +注:关于redis其他语言官方推荐的客户端可以在[客户端](http://www.redis.cn/clients.html)该网页查看,其中官方推荐的用了黄色星星:star:标注。 + +![redis官方推荐客户端](D:\spring-samples-for-all\pictures\redis官方推荐客户端.png) + + + +### 1.2 Redis可视化软件 + +推荐**Redis Desktop Manager** 作为可视化查看工具,可以直观看到用例中测试关于存储实体对象序列化的情况。 + +### 1.3 项目结构说明 + +1. jedis和redisson的配置和单元测试分别位于resources和test下对应的包中,其中集群的配置文件以cluster结尾。所有配置按照需要在springApplication.xml用import导入。 +2. 实体类Programmer.java用于测试Redisson序列化与反序列化 + +![spring+redis项目目录结构](D:\spring-samples-for-all\pictures\spring+redis项目目录结构.png) + +**springapplication.xml文件:** + +```xml + + + + + + + + + + + + + + + + +``` + +### 1.3 依赖说明 + +除了spring的基本依赖外,需要导入jedis 和 redisson 对应的客户端依赖包 + +```xml + + redis.clients + jedis + 3.0.0 + + + org.redisson + redisson + 3.9.1 + + + + io.netty + netty-all + 4.1.32.Final + +``` + + + +## 二、spring 整合 jedis + +#### 2.1 新建基本配置文件 + +```properties +redis.host=127.0.0.1 +redis.port=6379 +# 连接超时时间 +redis.timeout=2000 +# 最大空闲连接数 +redis.maxIdle=8 +# 最大连接数 +redis.maxTotal=16 +``` + +#### 2.2 单机配置 + +```xml + + + + + + + + + + + + + + + + + + + + + + + + +``` + +#### 2.3 集群配置 + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +#### 2.4 单机版本测试用例 + +1.需要注意的是,对于jedis而言,单机版本和集群版本注入的实例是不同的; + +2.jedis本身并不支持序列化于反序列化操作,如果需要存储实体类,需要序列化后存入。(redisson本身就支持序列化于反序列化,详见下文) + +```java +@RunWith(SpringRunner.class) +@ContextConfiguration({"classpath:springApplication.xml"}) +public class JedisSamples { + + @Autowired + private Jedis jedis; + + @Test + public void Set() { + jedis.set("hello", "spring"); + } + + @Test + public void Get() { + String s = jedis.get("hello"); + System.out.println(s); + } + + @Test + public void setEx() { + String s = jedis.setex("spring", 10, "我会在10秒后过期"); + System.out.println(s); + } + +} + +``` + +#### 2.5 集群版本测试用例 + +```java + +@RunWith(SpringRunner.class) +@ContextConfiguration({"classpath:springApplication.xml"}) +public class JedisClusterSamples { + + @Autowired + private JedisCluster jedisCluster; + + @Test + public void Set() { + jedisCluster.set("hello", "spring"); + } + + @Test + public void Get() { + String s = jedisCluster.get("hello"); + System.out.println(s); + } + + @Test + public void setEx() { + String s = jedisCluster.setex("spring", 10, "我会在10秒后过期"); + System.out.println(s); + } + +} +``` + + + +## 三、spring 整合 redisson + +#### 2.1 单机配置 + +```xml + + + + + + + + + + +``` + +#### 2.2 集群配置 + +```xml + + + + + + + + + + + + + +``` + +#### 2.3 存储基本类型测试用例 + +1. 这里需要注意的是,对于Redisson而言, 单机和集群最后在使用的时候注入的都是RedissonClient,这和jedis是不同的。 + +```java +@RunWith(SpringRunner.class) +@ContextConfiguration({"classpath:springApplication.xml"}) +public class RedissonSamples { + + @Autowired + private RedissonClient redissonClient; + + @Test + public void Set() { + // key 存在则更新 不存在则删除 + RBucket rBucket = redissonClient.getBucket("redisson"); + rBucket.set("firstValue"); + } + + @Test + public void Get() { + // key 存在则更新 不存在则删除 + RBucket rBucket = redissonClient.getBucket("redisson"); + System.out.println(rBucket.get()); + } + + @Test + public void SetEx() { + // key 存在则更新 不存在则删除 + RBucket rBucket = redissonClient.getBucket("redissonEx"); + rBucket.set("我在十秒后会消失", 10, TimeUnit.SECONDS); + } + + + @After + public void close() { + redissonClient.shutdown(); + } +} +``` + +#### 2.4 存储实体对象测试用例 + +```java +@RunWith(SpringRunner.class) +@ContextConfiguration({"classpath:springApplication.xml"}) +public class RedissonObjectSamples { + + @Autowired + private RedissonClient redissonClient; + + // Redisson的对象编码类是用于将对象进行序列化和反序列化 默认采用Jackson + + @Test + public void Set() { + RBucket rBucket = redissonClient.getBucket("programmer"); + rBucket.set(new Programmer("xiaoming", 12, 5000.21f, new Date())); + //存储结果: {"@class":"com.heibaiying.bean.Programmer","age":12,"birthday":["java.util.Date",1545714986590],"name":"xiaoming","salary":5000.21} + } + + @Test + public void Get() { + RBucket rBucket = redissonClient.getBucket("programmer"); + System.out.println(rBucket.get()); + } + + @After + public void close() { + redissonClient.shutdown(); + } +} + +``` + +## 附:Redis的数据结构和操作命令 + +### 1.1 预备 + +#### 1.1.1 全局命令 + +1. 查看所有键: **keys \*** + +2. 查看键总数:**dbsize** + +3. 检查键是否存在:**exists key** + +4. 删除键:**del key [key ...]** 支持删除多个键 + +5. 键过期:**expire key seconds** + + ttl命令会返回键的剩余过期时间, 它有3种返回值: + + - 大于等于0的整数: 键剩余的过期时间。 + - -1: 键没设置过期时间。 + - -2: 键不存在 + +6. 键的数据结构 **type key** + +#### 1.1.2 数据结构和内部编码 + +type命令实际返回的就是当前键的数据结构类型, 它们分别是:**string**(字符串) 、 **hash**(哈希) 、 **list**(列表) 、 **set**(集合) 、 **zset**(有序集合) + +#### 1.1.3 单线程架构 + +1. 纯内存访问, Redis将所有数据放在内存中, 内存的响应时长大约为100纳秒, 这是Redis达到每秒万级别访问的重要基础。 +2. 非阻塞I/O, Redis使用epoll作为I/O多路复用技术的实现, 再加上Redis自身的事件处理模型将epoll中的连接、 读写、 关闭都转换为事件, 不在网络I/O上浪费过多的时间, 如图2-6所示。 +3. 单线程避免了线程切换和竞态产生的消耗。 + +### 1.2 字符串 + +| 作用 | 格式 | 参数或示例 | +| ---------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 设置值 | set key value \[ex seconds]\[px milliseconds][nx\|xx] setnx setex | ex seconds: 为键设置秒级过期时间。
px milliseconds: 为键设置毫秒级过期时间。
nx: 键必须不存在, 才可以设置成功, 用于添加。
xx: 与nx相反, 键必须存在, 才可以设置成功, 用于更新。 | +| 获取值 | get key | r如果获取的键不存在 ,则返回nil(空) | +| 批量设置 | mset key value [key value ...] | mset a 1 b 2 c 3 d 4 | +| 批量获取值 | mget key [key ...] | mget a b c d | +| 计数 | incr key decr key incrby key increment(指定数值自增)
decrby key decrement(指定数值自减)
incrbyfloat key increment (浮点数自增) | 值不是整数, 返回错误。 值是整数, 返回自增或自减后的结果。
键不存在,创建键,并按照值为0自增或自减, 返回结果为1。 | +| 追加值 | append key value | 向字符串的默认追加值 | +| 字符串长度 | strlen key | 获取字符串长度,中文占用三个字节 | +| 设置并返回原值 | getset key value | | +| 设置指定位置的租字符串 | setrange key offeset value | | +| 获取部分字符串 | getrange key start end | | + +### 1.3 哈希 + +| 作用 | 格式 | 参数或示例 | +| ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 设置值 | hset key field value | hset user:1 name tom
hset user:1 age 12 | +| 获取值 | hget key field | hget user:1 name | +| 删除field | hdel key field [field ...] | | +| 计算field个数 | hlen key | | +| 批量设置或获取field-value | hmget key field [field]
hmset key field value [field value...] | hmset user:1 name mike age 12 city tianjin
hmget user:1 name city | +| 判断field是否存在 | hexists key field | | +| 获取所有field | hkeys key | | +| 获取所有value | hvals key | | +| 获取所有的filed-value | hgetall key | 如果哈希元素个数比较多, 会存在阻塞Redis的可能。
获取全部 可以使用hscan命令, 该命令会渐进式遍历哈希类型 | +| 计数 | hincrby key field
hincrbyfloat key field | | + +### 1.4 列表 + +| 作用 | 格式 | 参数或示例 | +| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 增 | 左侧插入:lpush key value [value ...] 右侧插入:rpush key value [value ...] 某个指定元素前后插入:linsert key before\|after pivot value | | +| 查 | 获取指定范围内的元素列表:lrange key start end 获取列表指定索引下标的元素:lindex key index 获取列表指定长度:llen key | lrange listkey 0 -1 | +| 删 | 从列表左侧弹出元素:lpop key 从列表右侧弹出元素:rpop key 删除指定元素:lrem key count value 截取列表:ltrim key start end | count>0, 从左到右, 删除最多count个元素。
count<0, 从右到左, 删除最多count绝对值个元素。
count=0, 删除所有 | +| 改 | 修改指定索引下标的元素:lset key index newValue | | +| 阻塞操作 | blpop key [key ...] timeout brpop key [key ...] timeout | key[key...]: 多个列表的键。 timeout: 阻塞时间\|等待时间(单位: 秒) | + + + +### 1.5 集合 + +集合(set) 类型也是用来保存多个的字符串元素, 但和列表类型不一样的是, **集合中不允许有重复元素**, 并且集合中的元素是无序的, **不能通过索引下标获取元素**。 + +**集合内操作**: + +| 作用 | 格式 | 参数或示例 | +| -------------------- | ------------------------------ | ----------------------------------------- | +| 添加元素 | sadd key element [element ...] | 返回结果为添加成功的元素个数 | +| 删除元素 | srem key element [element ...] | 返回结果为成功删除的元素个数 | +| 计算元素个数 | scard key | | +| 判断元素是否在集合中 | sismember key element | | +| 随机返回 | srandmember key [count] | 随机从集合返回指定个数元素,count 默认为1 | +| 从集合随机弹出元素 | spop key | srandmember 不会从集合中删除元素,spop 会 | +| 获取集合中所有元素 | smembers key | 可用sscan 代替 | + +**集合间操作**: + +| 作用 | 格式 | +| ---------------------------- | ------------------------------------------------------------ | +| 求多个集合的交集 | sinter key [key ...] | +| 求多个集合的并集 | suinon key [key ...] | +| 求多个集合的差集 | sdiff key [key ...] | +| 将交集、并集、差集的结果保存 | sinterstore destination key [key ...]
suionstore destination key [key ...]
sdiffstore destination key [key ...] | + +### 1.6 有序集合 + +有序集合中的元素可以排序。 但是它和列表使用索引下标作为排序依据不同的是, 它给每个元素设置一个分数(score) 作为排序的依据。 + +**集合内操作**: + +| 作用 | 格式 | 参数或示例 | +| ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 添加成员 | zadd key score member [score member ...] | nx: member必须不存在, 才可设置成功, 用于添加。
xx: member必须存在, 才可以设置成功, 用于更新。
ch: 返回此次操作后, 有序集合元素和分数发生变化的个数
incr: 对score做增加, 相当于后面介绍的zincrby。 | +| 计算成员个数 | zcard key | | +| 计算某个成员的分数 | zscore key member | | +| 计算某个成员的排名 | zrank key member zrevrank key member | zrank是从分数从低到高返回排名, zrevrank反之。 | +| 删除成员 | zrem key member [member ...] | | +| 增加成员分数 | zincrby key increment member | zincrby user:ranking 9 tom | +| 返回指定排名范围的成员 | zrange key start end [withscores] zrange key start end [withscores] | zrange是从低到高返回, zrevrange反之。 | +| 返回指定分数范围内的成员 | zrangebyscore key min max \[withscores][limit offset count] zrevrangebyscore key max min \[withscores][limit offset count] | 其中zrangebyscore按照分数从低到高返回, zrevrangebyscore反之。 [limit offset count]选项可以限制输出的起始位置和个数: 同时min和max还支持开区间(小括号) 和闭区间(中括号) , -inf和+inf分别代表无限小和无限大 | +| 删除指定排名内的升序元素 | zremrangerank key start end | | +| 删除指定分数范围的成员 | zremrangebyscore key min max | | + +**集合间操作**: + +| 作用 | 格式 | +| ---- | ------------------------------------------------------------ | +| 交集 | zinterstore destination numkeys key \[key ...] [weights weight [weight ...]] \[aggregate sum\|min\|max] | +| 并集 | zunionstore destination numkeys key \[key ...] [weights weight [weight ...]] \[aggregate sum\|min\|max] | + +- destination: 交集计算结果保存到这个键。 +- numkeys: 需要做交集计算键的个数。 +- key[key...]: 需要做交集计算的键。 +- weights weight[weight...]: 每个键的权重, 在做交集计算时, 每个键中的每个member会将自己分数乘以这个权重, 每个键的权重默认是1。 +- aggregate sum|min|max: 计算成员交集后, 分值可以按照sum(和) 、min(最小值) 、 max(最大值) 做汇总, 默认值是sum。 + +### 1.7 键管理 + +#### 1.7.1 单个键管理 + +##### 1.键重命名 + +**rename key newkey** + + 为了防止被强行rename, Redis提供了renamenx命令, 确保只有newKey不存在时候才被覆盖。 + +##### 2. 随机返回键 + + **random key** + +##### 3.键过期 + +- expire key seconds: 键在seconds秒后过期。 +- expireat key timestamp: 键在秒级时间戳timestamp后过期。 +- pexpire key milliseconds: 键在milliseconds毫秒后过期。 +- pexpireat key milliseconds-timestamp键在毫秒级时间戳timestamp后过期 + +注意: + +1. 如果expire key的键不存在, 返回结果为0 +2. 如果设置过期时间为负值, 键会立即被删除, 犹如使用del命令一样 +3. persist key t命令可以将键的过期时间清除 +4. 对于字符串类型键, 执行set命令会去掉过期时间, 这个问题很容易在开发中被忽视 +5. Redis不支持二级数据结构(例如哈希、 列表) 内部元素的过期功能, 例如不能对列表类型的一个元素做过期时间设置 +6. setex命令作为set+expire的组合, 不但是原子执行, 同时减少了一次网络通讯的时间 + +#### 1.7.2 键遍历 + +##### 1. 全量键遍历 + +**keys pattern** + +##### 2. 渐进式遍历 + +scan cursor \[match pattern] \[count number] + +- cursor是必需参数, 实际上cursor是一个游标, 第一次遍历从0开始, 每次scan遍历完都会返回当前游标的值, 直到游标值为0, 表示遍历结束。 +- match pattern是可选参数, 它的作用的是做模式的匹配, 这点和keys的模式匹配很像。 +- count number是可选参数, 它的作用是表明每次要遍历的键个数, 默认值是10, 此参数可以适当增大。 + +#### 1.7.3 数据库管理 + +##### 1.切换数据库 + +**select dbIndex** + +##### 2.flushdb/flushall + +flushdb/flushall命令用于清除数据库, 两者的区别的是flushdb只清除当前数据库, flushall会清除所有数据库。 \ No newline at end of file diff --git a/spring/spring-redis/src/main/resources/jedis/jedis.properties b/spring/spring-redis/src/main/resources/jedis/jedis.properties index f25cf51..1a0357d 100644 --- a/spring/spring-redis/src/main/resources/jedis/jedis.properties +++ b/spring/spring-redis/src/main/resources/jedis/jedis.properties @@ -1,5 +1,8 @@ redis.host=127.0.0.1 redis.port=6379 +# ӳʱʱ redis.timeout=2000 +# redis.maxIdle=8 +# redis.maxTotal=16 \ No newline at end of file diff --git a/spring/spring-redis/src/main/resources/jedis/jedis.xml b/spring/spring-redis/src/main/resources/jedis/jedis.xml index 431cdbd..4c91504 100644 --- a/spring/spring-redis/src/main/resources/jedis/jedis.xml +++ b/spring/spring-redis/src/main/resources/jedis/jedis.xml @@ -22,7 +22,7 @@
- - + + \ No newline at end of file diff --git a/spring/spring-redis/src/main/resources/redisson/redisson.xml b/spring/spring-redis/src/main/resources/redisson/redisson.xml index a1ebd49..85ce254 100644 --- a/spring/spring-redis/src/main/resources/redisson/redisson.xml +++ b/spring/spring-redis/src/main/resources/redisson/redisson.xml @@ -9,8 +9,8 @@ - +