谈到Redis,大家应该都不陌生。它是用c语言开发的一个高性能键值数据库,主要用于缓存领域。本章通过Redis的安装,Redis的五大数据类型,Redis的Java客户端,Redis与Spring 的整合 。来让读者对它有一个初步的了解。下一章再通过介绍配置文件来搭建Redis的主从模式和集群模式(配置大于编程,先从简单的编程入手)。
效果图:
需求:对商品类目进行Redis缓存处理 Redis 安装
安装文档: Redis 五大数据类型
Redis 五大数据类型有String 类型,Hash 类型,List 类型,Set 类型,Zset(Sortedset)类型。其中常用的是前三个。 String 类型
String 是 redis 最基本的类型,一个key对应一个value。 127.0.0.1:6379> set key value OK 127.0.0.1:6379> get key "value" 127.0.0.1:6379> mset key1 1 key2 2 key3 3 OK 127.0.0.1:6379> mget key1 key3 1) "1" 2) "3" 127.0.0.1:6379> del key (integer) 1 127.0.0.1:6379> incr count (integer) 1 127.0.0.1:6379> incrby count 10 (integer) 11 127.0.0.1:6379> decr count (integer) 10 127.0.0.1:6379> decrby count 5 (integer) 5 127.0.0.1:6379> set str itdragon OK 127.0.0.1:6379> append str " blog!" (integer) 14 127.0.0.1:6379> get str "itdragon blog!" 127.0.0.1:6379> strlen str (integer) 14 Hash 散列类型
Redis hash 是一个键值对集合,和Java 的HashMap 类似。 127.0.0.1:6379> hset user name itdragon (integer) 1 127.0.0.1:6379> hget user name "itdragon" 127.0.0.1:6379> hmset user position java study redis OK 127.0.0.1:6379> hmget user position study 1) "java" 2) "redis" 127.0.0.1:6379> hgetall user 1) "name" 2) "itdragon" 3) "position" 4) "java" 5) "study" 6) "redis" 127.0.0.1:6379> hdel user name (integer) 1 127.0.0.1:6379> hdel user position study (integer) 2 127.0.0.1:6379> hexists user name (integer) 1 127.0.0.1:6379> hexists user age (integer) 0 127.0.0.1:6379> hkeys user 1) "name" 2) "position" 3) "study" 127.0.0.1:6379> hvals user 1) "itdragon" 2) "java" 3) "redis" 127.0.0.1:6379> hlen user (integer) 3 List 类型
Redis 列表是采用来链表来存储的简单字符串列表,按照插入顺序排序。添加元素一般从链表两端开始。 127.0.0.1:6379> lpush list 1 2 (integer) 2 127.0.0.1:6379> rpush list 3 4 (integer) 4 127.0.0.1:6379> lrange list 0 -1 1) "2" 2) "1" 3) "3" 4) "4" 127.0.0.1:6379> lpop list "2" 127.0.0.1:6379> rpop list "4" 127.0.0.1:6379> llen list (integer) 2 127.0.0.1:6379> lindex list 1 "3" 127.0.0.1:6379> linsert list after 1 2 (integer) 3 127.0.0.1:6379> linsert list before 3 4 (integer) 4 127.0.0.1:6379> ltrim list 0 1 OK 127.0.0.1:6379> rpoplpush list newlist "1" Set 类型
Redis 的 Set 是String类型的无序集合。它是通过HashTable实现实现的,用法和 List 类型很相似。 127.0.0.1:6379> sadd set a b c d (integer) 4 127.0.0.1:6379> srem set a b c (integer) 3 127.0.0.1:6379> smembers set 1) "d" 127.0.0.1:6379> sismember set a (integer) 0 127.0.0.1:6379> sismember set d (integer) 1 127.0.0.1:6379> sadd setA 1 2 3 (integer) 3 127.0.0.1:6379> sadd setB 2 3 4 (integer) 3 127.0.0.1:6379> sdiff setA setB 1) "1" 127.0.0.1:6379> sdiff setB setA 1) "4" 127.0.0.1:6379> sinter setA setB 1) "2" 2) "3" 127.0.0.1:6379> sunion setA setB 1) "1" 2) "2" 3) "3" 4) "4" 127.0.0.1:6379> scard setA (integer) 3 Zset 类型
Redis 的 zset(sorted set)和 set 一样也是string类型元素的集合,且不允许有重复的成员。不同的是 zset 的每个元素都会关联一个double类型的分数。zset正是通过分数来为集合中的成员进行排序。zset的成员是唯一的,但分数(score)却可以重复。 127.0.0.1:6379> zadd zset 65 A 67 C 66 B (integer) 3 127.0.0.1:6379> zscore zset C "67" 127.0.0.1:6379> zrange zset 0 -1 1) "A" 2) "B" 3) "C" 127.0.0.1:6379> zrevrange zset 0 -1 1) "C" 2) "B" 3) "A" 127.0.0.1:6379> zrevrange zset 0 -1 withscores 1) "C" 2) "67" 3) "B" 4) "66" 5) "A" 6) "65" 127.0.0.1:6379> zrank zset C (integer) 2 127.0.0.1:6379> zrevrank zset C (integer) 0 127.0.0.1:6379> zrangebyscore zset 65 66 1) "A" 2) "B" 127.0.0.1:6379> zrangebyscore zset 65 66 limit 1 2 1) "B" 127.0.0.1:6379> zincrby zset 10 A "75" 127.0.0.1:6379> zcard zset (integer) 3 127.0.0.1:6379> zcount zset 65 66 (integer) 1 127.0.0.1:6379> zremrangebyrank zset 0 1 (integer) 2 127.0.0.1:6379> zremrangebyscore zset 100 200 (integer) 0 127.0.0.1:6379> zrem zset A (integer) 1 Jedis客户端
Jedis 是比较主流的 Redis Java 客户端。 <!-- Redis客户端 --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <jedis.version>2.7.2</jedis.version> </dependency>
第二步:单元测试类 package com.itdragon.redis; import java.util.HashMap; import java.util.Map; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.Test; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; public class TestJedisOperate { private final static String HOST = "112.74.83.71"; private final static int PORT = 6379; /** * jedis 的语法和 redis 的语法几乎一致,比较常用的有Hash,String,List */ @Test public void jedisSignle() { Jedis jedis = new Jedis(HOST, PORT); jedis.set("account", "itdragon"); System.out.println("set , get 操作 : " + jedis.get("account")); jedis.mset("account:01", "itdragon01", "account:02", "itdragon02"); System.out.println("mset , mget 操作 : " + jedis.mget("account:01", "account:02")); jedis.hset("user", "name", "ITDragon"); System.out.println("hset , hget 操作 : " + jedis.hget("user", "name")); Map<String, String> userMap = new HashMap<>(); userMap.put("password", "123456"); userMap.put("position", "Java"); jedis.hmset("user", userMap); System.out.println("hmset , hmget 操作 : " + jedis.hmget("user", "name", "password", "position")); if (0 == jedis.llen("userList")) { jedis.lpush("userList", "1", "2", "3"); } System.out.println("List 类型 lpush , lrange 操作 : " + jedis.lrange("userList", 0, -1)); jedis.sadd("userSet", "1", "2", "2"); System.out.println("Set 类型 sadd , smembers 操作 : " + jedis.smembers("userSet")); Map<String, Double> scoreMembers = new HashMap<>(); scoreMembers.put("A", 65.0); scoreMembers.put("C", 67.0); scoreMembers.put("B", 66.0); jedis.zadd("userScore", scoreMembers); System.out.println("Set 类型 zadd , zrange 操作 : " + jedis.zrange("userScore", 0, -1)); jedis.close(); } @Test public void testJedisPool() { JedisPool pool = new JedisPool(HOST, PORT); Jedis jedis = pool.getResource(); System.out.println("通过连接池获取 key 为 account 的值 : " + jedis.get("account")); jedis.close(); pool.close(); } } Spring 整合 Redis
创建用于整合redis的文件 applicationContext-jedis.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!-- 加载配置文件 --> <context:property-placeholder location="classpath:resource/*.properties" /> <!-- 连接池配置 (可以用 redis 默认配置,效果可能会更好)--> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 最大连接数 --> <property name="maxTotal" value="30" /> <!-- 最大空闲连接数 --> <property name="maxIdle" value="10" /> <!-- 每次释放连接的最大数目 --> <property name="numTestsPerEvictionRun" value="1024" /> <!-- 释放连接的扫描间隔(毫秒) --> <property name="timeBetweenEvictionRunsMillis" value="30000" /> <!-- 连接最小空闲时间 --> <property name="minEvictableIdleTimeMillis" value="1800000" /> <!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 --> <property name="softMinEvictableIdleTimeMillis" value="10000" /> <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 --> <property name="maxWaitMillis" value="1500" /> <!-- 在获取连接的时候检查有效性, 默认false --> <property name="testOnBorrow" value="true" /> <!-- 在空闲时检查有效性, 默认false --> <property name="testWhileIdle" value="true" /> <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true --> <property name="blockWhenExhausted" value="false" /> </bean> <!-- jedis客户端单机版 --> <bean id="redisClient" class="redis.clients.jedis.JedisPool"> <constructor-arg name="host" value="${redis.host}" /> <constructor-arg name="port" value="${redis.ip}" /> <!-- <constructor-arg name="poolConfig" ref="jedisPoolConfig" /> --> </bean> <bean id="jedisClient" class="com.itdragon.common.utils.JedisClientSingle"/> </beans> 简单封装了Jedis 常用方法 JedisClientSingle.java package com.itdragon.common.utils; import org.springframework.beans.factory.annotation.Autowired; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; // 单例的Redis 工具类 public class JedisClientSingle { /** * connect timed out 问题: * 1. 检查redis服务是否开启 * 2. 检查是否是因为防火墙的问题 * 3. 检查网络问题(如果在同一个局域网内几乎不会出现这个问题) * Jedis jedis =new Jedis(HOST,PORT,100000); * JedisPool pool = new JedisPool(poolConfig, HOST, PORT, 100000); */ @Autowired private JedisPool jedisPool; public String get(String key) { Jedis jedis = jedisPool.getResource(); String string = jedis.get(key); jedis.close(); return string; } public String set(String key, String value) { Jedis jedis = jedisPool.getResource(); String string = jedis.set(key, value); jedis.close(); return string; } public String hget(String hkey, String key) { Jedis jedis = jedisPool.getResource(); String string = jedis.hget(hkey, key); jedis.close(); return string; } public long hset(String hkey, String key, String value) { Jedis jedis = jedisPool.getResource(); Long result = jedis.hset(hkey, key, value); jedis.close(); return result; } public long del(String key) { Jedis jedis = jedisPool.getResource(); Long result = jedis.del(key); jedis.close(); return result; } public long hdel(String hkey, String key) { Jedis jedis = jedisPool.getResource(); Long result = jedis.hdel(hkey, key); jedis.close(); return result; } } 获取商品类名接口实现类 ProductCategoryServiceImpl.java package com.itdragon.service.impl; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.util.CollectionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.itdragon.common.pojo.EUTreeNode; import com.itdragon.common.pojo.ResponseResult; import com.itdragon.common.utils.JedisClientSingle; import com.itdragon.common.utils.JsonUtils; import com.itdragon.mapper.ProductCategoryMapper; import com.itdragon.pojo.ProductCategory; import com.itdragon.pojo.ProductCategoryExample; import com.itdragon.pojo.ProductCategoryExample.Criteria; import com.itdragon.service.ProductCategoryService; @Service public class ProductCategoryServiceImpl implements ProductCategoryService { @Autowired private ProductCategoryMapper categoryMapper; @Autowired private JedisClientSingle jedisClientSingle; @Value("${CATEGROY_ID_CACHE_REDIS_KEY}") private String CATEGROY_ID_CACHE_REDIS_KEY; @Override public List<EUTreeNode> getCategoryList(Long parentId) { long startTime = System.currentTimeMillis(); List<EUTreeNode> resultList = new ArrayList<>(); // 从redis缓存中取内容 try { String cacheDatas = jedisClientSingle.hget(CATEGROY_ID_CACHE_REDIS_KEY, parentId.toString()); if (StringUtils.isNotBlank(cacheDatas)) { List<ProductCategory> categories = JsonUtils.jsonToList(cacheDatas, ProductCategory.class); for (ProductCategory category : categories) { EUTreeNode node = new EUTreeNode(); node.setId(category.getId()); node.setText(category.getName()); node.setState(category.getIsParent()?"closed":"open"); resultList.add(node); } System.out.println("redis cache Time : " + (System.currentTimeMillis() - startTime)); return resultList; } } catch (Exception e) { e.printStackTrace(); } ProductCategoryExample example = new ProductCategoryExample(); Criteria criteria = example.createCriteria(); criteria.andStatusEqualTo(1); criteria.andParentIdEqualTo(parentId); // 查询父节点下的所有子节点 List<ProductCategory> productCategories = categoryMapper.selectByExample(example); for (ProductCategory category : productCategories) { EUTreeNode node = new EUTreeNode(); node.setId(category.getId()); node.setText(category.getName()); node.setState(category.getIsParent()?"closed":"open"); resultList.add(node); } System.out.println("No redis cache Time : " + (System.currentTimeMillis() - startTime)); // 向redis缓存中添加内容 try { jedisClientSingle.hset(CATEGROY_ID_CACHE_REDIS_KEY, parentId.toString(), JsonUtils.objectToJson(productCategories)); } catch (Exception e) { e.printStackTrace(); } return resultList; } // 后面的内容看源码... } 源码:https://github.com/ITDragonBlog/daydayup/tree/master/Redis 到这里,Redis 的快速入门就结束了。下一章节介绍Redis 的主从和集群。 (责任编辑:IT) |