一、jedis****操作:
1、POM依赖:
1 <dependency>
2 <groupId>redis.clients</groupId>
3 <artifactId>jedis</artifactId>
4 <version>2.5.0</version>
5 </dependency>
2、建一个连接redis数据库的工具类:
1 public class RedisUtil {
2
3 //服务器IP地址
4 private static String ADDR = "x.x.x.x";
5
6 //端口
7 private static int PORT = 6379;
8 //密码
9 private static String AUTH = "123456";
10 //连接实例的最大连接数
11 private static int MAX_ACTIVE = 1024;
12
13 //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
14 private static int MAX_IDLE = 200;
15
16 //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException
17 private static int MAX_WAIT = 10000;
18
19 //连接超时的时间
20 private static int TIMEOUT = 10000;
21
22 // 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
23 private static boolean TEST_ON_BORROW = true;
24
25 private static JedisPool jedisPool = null;
26
27 /**
28 * 初始化Redis连接池
29 */
30
31 static {
32
33 try {
34
35 JedisPoolConfig config = new JedisPoolConfig();
36 config.setMaxTotal(MAX_ACTIVE);
37 config.setMaxIdle(MAX_IDLE);
38 config.setMaxWaitMillis(MAX_WAIT);
39 config.setTestOnBorrow(TEST_ON_BORROW);
40 jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
41
42 } catch (Exception e) {
43
44 e.printStackTrace();
45 }
46
47 }
48
49 /**
50 * 获取Jedis实例
51 */
52
53 public synchronized static Jedis getJedis() {
54
55 try {
56
57 if (jedisPool != null) {
58 Jedis resource = jedisPool.getResource();
59 return resource;
60 } else {
61 return null;
62 }
63
64 } catch (Exception e) {
65 e.printStackTrace();
66 return null;
67 }
68
69 }
70
71 /***
72 *
73 * 释放资源
74 */
75
76 public static void returnResource(final Jedis jedis) {
77 if(jedis != null) {
78 jedisPool.returnResource(jedis);
79 }
80
81 }
82 }
3、实现redis的增删改查:
1 public class TestRedis {
2
3 private Jedis jedis;
4
5 /**
6 * 连接redis服务器
7 */
8 public void connectRedis() {
9 jedis=RedisUtil.getJedis();
10 }
11
12 /**
13 * redis操作字符串
14 */
15 public void testString() {
16 //添加数据
17 jedis.set("name", "youcong");
18 System.out.println(jedis.get("name"));
19
20 //拼接字符串
21 jedis.append("name", ".com");
22 System.out.println(jedis.get("name"));
23
24 //删除数据
25 jedis.del("name");
26 System.out.println(jedis.get("name"));
27
28 //设置多个键值对
29 jedis.mset("name","yc","age","22","qq","1933108196");
30 jedis.incr("age");//加1操作
31 System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" +jedis.get("qq"));
32 }
33
34
35 /**
36 * redis操作map集合
37 */
38 public void testMap() {
39 //添加数据
40 Map<String,String> map = new HashMap<String,String>();
41
42 map.put("name", "yc");
43 map.put("age", "22");
44 map.put("qq", "1933108196");
45 jedis.hmset("user", map);
46
47 //取出users中的Name,执行结果:[minxr]-->注意结果是一个泛型的List
48 //第一个参数是存入redis中map对象的key,后面跟的是放入map中对象的key,后面的key可以是多个,是可变的
49 List<String> rsmap = jedis.hmget("user", "name","age","qq");
50 System.out.println(rsmap);
51
52
53 //删除map中的某个键值
54 jedis.hdel("user", "age");
55 System.out.println(jedis.hmget("user", "age"));//因为删除了,所以返回的是Null
56 System.out.println(jedis.hlen("user"));//返回key为user的键中存放的值的个数2
57 System.out.println(jedis.exists("user"));//是否存在key为user的记录,返回true
58 System.out.println(jedis.hkeys("user"));//返回map对象中的所有key
59 System.out.println(jedis.hvals("user"));//返回map对象中的所有value
60
61 Iterator<String> iter = jedis.hkeys("user").iterator();
62 while(iter.hasNext()) {
63 String key = iter.next();
64 System.out.println(key+":" + jedis.hmget("user", key));
65 }
66
67 }
68
69 /**
70 * redis操作List集合
71 */
72 public void testList() {
73 //开始前,先移除所有的内容
74 jedis.del("java framework");
75 System.out.println(jedis.lrange("java framework", 0, -1));
76
77 //先向key java framework 中存放三条数据
78 jedis.lpush("java framework","spring");
79 jedis.lpush("java framework", "struts");
80 jedis.lpush("java framework", "hibernate");
81
82 //再取出所有数据jedis.lrange是按范围取出
83 //第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有
84 System.out.println(jedis.lrange("java framework", 0, -1));
85
86 jedis.del("java framework");
87 jedis.rpush("java framework", "spring");
88 jedis.rpush("java framework", "struts");
89 jedis.rpush("java framework","hibernate");
90 System.out.println(jedis.lrange("java framework", 0, -1));
91
92
93 }
94
95
96 /**
97 * redis操作set集合
98 *
99 */
100
101 public void testSet() {
102
103 //添加
104 jedis.sadd("user", "liuling");
105 jedis.sadd("user", "xinxin");
106 jedis.sadd("user","ling");
107 jedis.sadd("user", "zhangxinxin");
108 jedis.sadd("user", "who");
109
110 //删除
111 jedis.srem("user", "who");
112 System.out.println(jedis.smembers("user"));//获取所有加入的value
113 System.out.println(jedis.sismember("user", "who"));//判断who是否是user集合的元素
114 System.out.println(jedis.srandmember("user"));
115 System.out.println(jedis.scard("user"));//返回集合的元素个数
116 }
117
118
119 /**
120 * redis排序
121 */
122
123 public void testSort() {
124
125 //jedis 排序
126 //注意,此处的rpush和lpush是List的操作。是一个双向链表(但从表现来看的)
127 jedis.del("a");//先清除数据,再加入数据进行测试
128 jedis.rpush("a", "1");
129 jedis.lpush("a", "6");
130 jedis.lpush("a", "3");
131 jedis.lpush("a", "9");
132 System.out.println(jedis.lrange("a", 0, -1));
133 System.out.println(jedis.sort("a"));//[1,3,6,9] //输入排序后结果
134 System.out.println(jedis.lrange("a", 0, -1));
135 }
136
137
138 /**
139 * redis连接池
140 */
141
142 public void testRedisPool() {
143
144 RedisUtil.getJedis().set("newname", "test");
145
146 System.out.println(RedisUtil.getJedis().get("newname"));
147 }
148
149 public static void main(String[] args) {
150 TestRedis test = new TestRedis();
151 test.connectRedis();
152 test.testSort();
153 }
154 }
二、关于spring-data-redis:
1. 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
2. 针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
ValueOperations:简单K-V操作
SetOperations:set类型数据操作
ZSetOperations:zset类型数据操作
HashOperations:针对map类型的数据操作
ListOperations:针对list类型的数据操作
3. 提供了对key的“bound”(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key,即BoundKeyOperations:
BoundValueOperations
BoundSetOperations
BoundListOperations
BoundSetOperations
BoundHashOperations
4. 将事务操作封装,有容器控制。
5. 针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)
JdkSerializationRedisSerializer:POJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。是目前最常用的序列化策略。
StringRedisSerializer:Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。
JacksonJsonRedisSerializer:jackson-json工具提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。【需要jackson-mapper-asl工具支持】
OxmSerializer:提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。【需要spring-oxm模块的支持】
三、Spring boot使用RestTemplate****:
1、POM依赖:
1 <dependencies>
2 <!-- spring boot 配置 -->
3 <dependency>
4 <groupId>org.springframework.boot</groupId>
5 <artifactId>spring-boot-starter-web</artifactId>
6 </dependency>
7
8 <dependency>
9 <groupId>org.springframework.boot</groupId>
10 <artifactId>spring-boot-starter-thymeleaf</artifactId>
11 </dependency>
12
13 <dependency>
14 <groupId>org.springframework.boot</groupId>
15 <artifactId>spring-boot-starter-test</artifactId>
16 <scope>test</scope>
17 </dependency>
18
19 <dependency>
20 <groupId>org.springframework.boot</groupId>
21 <artifactId>spring-boot-starter-data-redis</artifactId>
22 </dependency>
23 </dependencies>
2、配置文件application.properties:
1 # Redis数据库索引(默认为0)
2 spring.redis.database=0
3 # Redis服务器地址
4 spring.redis.host=127.0.0.1
5 # Redis服务器连接端口
6 spring.redis.port=6379
7 # Redis服务器连接密码(默认为空)
8 spring.redis.password=
9 # 连接池最大连接数(使用负值表示没有限制)
10 spring.redis.pool.max-active=8
11 # 连接池最大阻塞等待时间(使用负值表示没有限制)
12 spring.redis.pool.max-wait=-1
13 # 连接池中的最大空闲连接
14 spring.redis.pool.max-idle=8
15 # 连接池中的最小空闲连接
16 spring.redis.pool.min-idle=0
17 # 连接超时时间(毫秒)
18 spring.redis.timeout=0
3、redis操作工具类:
1 @Component
2 public class RedisService {
3 @Autowired
4 private RedisTemplate<String, String> redisTemplate;
5
6 /**
7 * 默认过期时长,单位:秒
8 */
9 public static final long DEFAULT_EXPIRE = 60 * 60 * 24;
10
11 /**
12 * 不设置过期时长
13 */
14 public static final long NOT_EXPIRE = -1;
15
16
17
18
19 public boolean existsKey(String key) {
20 return redisTemplate.hasKey(key);
21 }
22
23 /**
24 * 重名名key,如果newKey已经存在,则newKey的原值被覆盖
25 *
26 * @param oldKey
27 * @param newKey
28 */
29 public void renameKey(String oldKey, String newKey) {
30 redisTemplate.rename(oldKey, newKey);
31 }
32
33 /**
34 * newKey不存在时才重命名
35 *
36 * @param oldKey
37 * @param newKey
38 * @return 修改成功返回true
39 */
40 public boolean renameKeyNotExist(String oldKey, String newKey) {
41 return redisTemplate.renameIfAbsent(oldKey, newKey);
42 }
43
44 /**
45 * 删除key
46 *
47 * @param key
48 */
49 public void deleteKey(String key) {
50 redisTemplate.delete(key);
51 }
52
53 /**
54 * 删除多个key
55 *
56 * @param keys
57 */
58 public void deleteKey(String... keys) {
59 Set<String> kSet = Stream.of(keys).map(k -> k).collect(Collectors.toSet());
60 redisTemplate.delete(kSet);
61 }
62
63 /**
64 * 删除Key的集合
65 *
66 * @param keys
67 */
68 public void deleteKey(Collection<String> keys) {
69 Set<String> kSet = keys.stream().map(k -> k).collect(Collectors.toSet());
70 redisTemplate.delete(kSet);
71 }
72
73 /**
74 * 设置key的生命周期
75 *
76 * @param key
77 * @param time
78 * @param timeUnit
79 */
80 public void expireKey(String key, long time, TimeUnit timeUnit) {
81 redisTemplate.expire(key, time, timeUnit);
82 }
83
84 /**
85 * 指定key在指定的日期过期
86 *
87 * @param key
88 * @param date
89 */
90 public void expireKeyAt(String key, Date date) {
91 redisTemplate.expireAt(key, date);
92 }
93
94 /**
95 * 查询key的生命周期
96 *
97 * @param key
98 * @param timeUnit
99 * @return
100 */
101 public long getKeyExpire(String key, TimeUnit timeUnit) {
102 return redisTemplate.getExpire(key, timeUnit);
103 }
104
105 /**
106 * 将key设置为永久有效
107 *
108 * @param key
109 */
110 public void persistKey(String key) {
111 redisTemplate.persist(key);
112 }
113 }
4、缓存注解的使用:
(1) @Cacheable:在方法执行前Spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;没有则调用方法并将方法返回值放进缓存。
(2) @CachePut:将方法的返回值放到缓存中。
(3) @CacheEvict:删除缓存中的数据。
注意:
1)保存到缓存的DTO实体对象要实现Serializable接口,否则会报序列化的错误;
2)@CachePut注解的cacheNames 和 key 要跟 @Cacheable() 里的一致,才会正确更新,并且和@Cacheable() 注解的方法返回值要一致;
5、两个redis命令:
(1) SETNX:将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写。
(2) GETSET:GETSET可以和INCR一起使用实现支持重置的计数功能。举个例子:每当有事件发生的时候,一段程序都会调用INCR给key mycounter加1,但是有时我们需要获取计数器的值,并且自动将其重置为0。这可以通过GETSET mycounter “0”来实现;
如:
redis> INCR mycounter
(integer) 1
redis> GETSET mycounter "0"
"1"
redis> GET mycounter
"0"
6、redis实现的分布式锁:
1 @Component
2 @Slf4j
3 public class RedisLock {
4
5 @Autowired
6 StringRedisTemplate redisTemplate;
7
8 /**
9 * 加锁
10 * @param key
11 * @param value 当前时间 + 超时时间
12 * @return
13 */
14 public boolean lock(String key, String value){
15 if (redisTemplate.opsForValue().setIfAbsent(key, value)){
16 return true;
17 }
18
19 //解决死锁,且当多个线程同时来时,只会让一个线程拿到锁
20 String currentValue = redisTemplate.opsForValue().get(key);
21 //如果过期
22 if (!StringUtils.isEmpty(currentValue) &&
23 Long.parseLong(currentValue) < System.currentTimeMillis()){
24 //获取上一个锁的时间
25 String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
26 if (StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)){
27 return true;
28 }
29 }
30
31 return false;
32 }
33
34 /**
35 * 解锁
36 * @param key
37 * @param value
38 */
39 public void unlock(String key, String value){
40
41 try {
42 String currentValue = redisTemplate.opsForValue().get(key);
43 if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)){
44 redisTemplate.opsForValue().getOperations().delete(key);
45 }
46 }catch (Exception e){
47 log.error("【redis锁】解锁失败, {}", e);
48 }
49 }
50 }
四、参考资料:
https://www.cnblogs.com/youcong/p/8098881.html