key-value存储系统
字符串 SET GET
HASH HMSET HGETALL
列表(list) LPUSH LRANGE x m n (m to n)
集合(Set) SADD SMEMBERS
有序集合(sorted set) ZADD key 1 name ZRANGE key 0 10 WITHSCORES
发布订阅 订阅者:redis 127.0.0.1:6379> SUBSCRIBE redisChat
发布者:PUBLISH redisChat “Redis is a great caching technique”
Java 连接Redis实例
import redis.clients.jedis.Jedis;
public class RedisStringJava {
public static void main(String[] args) {
//连接本地的 Redis 服务
Jedis jedis = new Jedis("localhost");
System.out.println("连接成功");
//设置 redis 字符串数据
jedis.set("runoobkey", "www.runoob.com";);
// 获取存储的数据并输出
System.out.println("redis 存储的字符串为: "+ jedis.get("runoobkey"));
}
}
Redis添加缓存有两种方式,一种是set,另一种是hset,这两种方式的不同之处是hset可以对key进行分类,查询的时候先查询类,然后再在该类下查询某个key的值,这样的效率肯定要比set方式存储的数据查询效率高。因此我们选择hset的方式来存储缓存信息。
Redis优缺点
1.读写速度快
2.支持持久化(AOF和RBD两种方式)
3.支持事务
4.支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
5.数据结构丰富:除了支持string类型的value外还支持string、hash、set、sortedset、list等数据结构。
缺点:
1 Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
2 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
3 Redis的主从复制采用全量复制,复制过程中主机会fork出一个子进程对内存做一份快照,并将子进程的内存快照保存为文件发送给从机,这一过程需要确保主机有足够多的空余内存。若快照文件较大,对集群的服务能力会产生较大的影响,而且复制过程是在从机新加入集群或者从机和主机网络断开重连时都会进行,也就是网络波动都会造成主机和从机间的一次全量的数据复制,这对实际的系统运营造成了不小的麻烦。
4 Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。
Linux安装Redis步骤以及遇到的一些问题
1.下载redis
wget http://download.redis.io/releases/redis-4.0.2.tar.gz
2.解压
3.make
4.make install
5.配置后端启动的方式 cp redis.conf /usr/local/redis/bin/
6.修改redis.conf 把daemonize的值由默认的no修改为yes,这个属性是用来指定是否后台运行的
7.启动redis
[root@redis bin]./redis-server 127.0.0.1 redis.conf
查看是否正常启动 ps -ef|grep redis
8.测试服务
[root@redis bin]# ./redis-cli
127.0.0.1:6379> ping
PONG
但此时发现telnet不通,这里要做一些配置
1.开启redis端口,修改防火墙配置文件
vi /etc/sysconfig/iptables
添加
-A RH-Firewall-1-INPUT -m state –state NEW -m tcp -p tcp –dport 6379 -j ACCEPT
重新加载规则
service iptables restart
2.修改redis配置文件 vim redis.conf 注释掉#bind 127.0.0.1
3.到这里还有一个问题,DENIED Redis is running in protected mode because protected mode is enabled…说明redis目前处于受保护模式,不允许非本地客户端链接
可以通过设置密码来解决
vim redis.conf 找到# requirepass foobared这一行,去掉注释,foobared设置成自己的密码
4.再测试一下jedis连接
@Test
public void testJedis() {
Jedis jedis = new Jedis("IP地址", 6379);
jedis.auth("password");//设置成刚才改的密码
jedis.set("jedis-key", "hello jedis!");
String result = jedis.get("jedis-key");
System.out.println(result);
jedis.close();
}
这就完成了
下面看一下Spring和redis的整合
public interface JedisClient {
// Redis SET命令用于在Redis键中设置一些字符串值
String set(String key, String value);
// 根据key去查询相应的值
String get(String key);
// 判断key在Redis缓存中是否存在
Boolean exists(String key);
// 设置key的过期时间
Long expire(String key, int seconds);
// Redis TTL 命令以秒为单位返回 key 的剩余过期时间
Long ttl(String key);
// Redis Incr 命令将 key 中储存的数字值增一
Long incr(String key);
/**
* Redis Hset 命令用于为哈希表中的字段赋值 。 如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作。 如果字段已经存在于哈希表中,旧值将被覆盖。
*
* @param key
* @param field
* @param value
* @return
*/
Long hset(String key, String field, String value);
// Redis Hget 命令用于返回哈希表中指定字段的值。
String hget(String key, String field);
// Redis Hdel 命令用于删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略。
Long hdel(String key, String... field);
}
public class JedisClientPool implements JedisClient {
@Autowired
private JedisPool jedisPool;
@Value("${redis.password}")
private String password;
/**
*
*/
@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
jedis.auth(password);
String result = jedis.set(key, value);
jedis.close();
return result;
}
@Override
public String get(String key) {
Jedis jedis = jedisPool.getResource();
jedis.auth(password);
String result = jedis.get(key);
jedis.close();
return result;
}
@Override
public Boolean exists(String key) {
Jedis jedis = jedisPool.getResource();
jedis.auth(password);
Boolean result = jedis.exists(key);
jedis.close();
return result;
}
@Override
public Long expire(String key, int seconds) {
Jedis jedis = jedisPool.getResource();
jedis.auth(password);
Long result = jedis.expire(key, seconds);
jedis.close();
return result;
}
@Override
public Long ttl(String key) {
Jedis jedis = jedisPool.getResource();
jedis.auth(password);
Long result = jedis.ttl(key);
jedis.close();
return result;
}
@Override
public Long incr(String key) {
Jedis jedis = jedisPool.getResource();
jedis.auth(password);
Long result = jedis.incr(key);
jedis.close();
return result;
}
@Override
public Long hset(String key, String field, String value) {
Jedis jedis = jedisPool.getResource();
jedis.auth(password);
Long result = jedis.hset(key, field, value);
jedis.close();
return result;
}
@Override
public String hget(String key, String field) {
Jedis jedis = jedisPool.getResource();
jedis.auth(password);
String result = jedis.hget(key, field);
jedis.close();
return result;
}
@Override
public Long hdel(String key, String... field) {
Jedis jedis = jedisPool.getResource();
jedis.auth(password);
Long result = jedis.hdel(key, field);
jedis.close();
return result;
}
}
在配置文件里面配置一下
<!-- 增加redis的properties文件 -->
<context:property-placeholder location="classpath:properties/redis.properties" />
<!-- redis单机版 -->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="${redis.host}"/>
<constructor-arg name="port" value="${redis.port}"/>
</bean>
<bean id="jedisClientPool" class="com.taotao.jedis.service.impl.JedisClientPool">
</bean>
下面在service处理对增删改查逻辑的时候加入使用缓存的逻辑
就贴一个吧
@Value("${INDEX_CONTENT}")
private String INDEX_CONTENT;
// 添加内容
@Override
public TaotaoResult addContent(TbContent content) {
content.setCreated(new Date());
content.setUpdated(new Date());
contentMapper.insert(content);
//添加缓存
jedisClient.hset(INDEX_CONTENT, content.getId().toString(), JSON.toJSONString(content));
return TaotaoResult.ok();
}