redis下载
官网没有window版的,这里可以window版本下载
https://github.com/tporadowski/redis/releases
官网下载
https://download.redis.io/releases/
运行redis
- 进入redis命令目录
redis-server.exe
运行服务,redis-cli.exe
运行客户端
命令的使用
遇到不会的,就在客户端打help
redis键
- Redis键是二进制的
- 很长的键不是一个好主意。
- 非常短的键通常不是一个好主意, 尝试坚持使用架构。例如,"object-type:id"是一个好主意,就像"user:1000"一样。
- 允许的最大密钥大小为 512 MB。
数据类型
- string
- list(有序的,用链表实现的,增删好,查询一般)
- hashes(哈希,键值对结构)
- set(无序的,唯一)
- sorted sets(无序的,唯一,这里的有序指根据分数进行排序; 排序集是通过包含跳过列表和哈希表的双端口数据结构实现;因此每次添加元素时,Redis都会执行O(log(N))操作;排序集适用于有大量更新的情况)
- bitmaps
- hyperLogLogs(HyperLogLog是一种概率数据结构,用于计算唯一事物(从技术上讲,这指的是估计集合的基数),我现在的理解是用更少的内存干与set相同的事,但并不存储元素,只是统计不同元素的个数)
操作数据的常用命令
字符串
- 设置值
set key value
- 获取值
get key
- 当值存在时,设置失败
set key newval nx
- 仅当值存在时。设置成功
set key newval xx
- incr增加1
incr num
- incrby增加指定数值
incrby num val
- 得到旧值并设置新值
getset num newval
- 一次设置多个值(m-> multi)
mset key1 val1 key2 val2 key3 val3
- 一次得到多个值,以数组形式
mget key1 key2 key3
- 判断值存在
exists key
- 删除值
del key
- 获取值的类型
type key
- 过期时间,到期自动删除,单位秒
expire key seconds
set key val ex seconds
- 查看剩余时间,单位秒
ttl key
- 过期时间,到期自动删除,单位毫秒
pexpire key millisecond
set key val px millisecond
- 查看剩余时间,单位毫秒
pttl key
列表
- 往链表头添加数据(lpush -> left push)
lpush key val1 val2 val3
- 往链表尾添加数据(rpush -> right push)
rpush key val1 val2 val3
- 获取链表的数据(lrange -> list range),获取所有数据: lrange 0 -1,从最后一个元素逆序遍历,最后一个元素为-1,倒数第二个元素为-2,依此类推
lrange start end
- 在左边弹出元素
lpop key
- 在右边弹出元素
rpop key
- 保留指定范围的元素
ltrim key satrt end
- 阻塞弹出元素(blpop -> block left pop)(链表无元素时阻塞请求, 达到指定时间返回,返回的数据形式为[key, val],因为此命令从多个链表拿元素,哪个链表先返回元素就返回哪个链表元素的key和val)
blpop key1 key2 seconds
brpop key1 kye2 seconds
- 获取链表的长度
llen key
哈希(hashes)
ps:操作方式挺像hbase
- 设置单个键对值(hset -> hashes set)
hset key filed value
- 获取
hget key field
- 设置多个键对值(hashes multi set )
hmset key fileld1 val1 fileld2 val2
- 获取
hmget key field1 fileld2
- 增加值(hincrby -> hashes increase by)
hincrby key fileld increment
集合(set)
- 添加
sadd key val1 val2 val3
- 获取所有
smembers key
- 检查某个元素是否在集合里(sismember ->set exists member)
sismember key member
- 随机弹出指定个数的随机元素
spop key count
- 求交集
sinter key1 key2 key3
- 求并集
sunion key1 key2 key3
ps: 要把结果存到另一个集合中,只需在命令后加store,例如sinterstore resultset key1 key2 key3
- 获取元素个数
scard key
- 获取指定个数的随机元素且不删除
srandmember key count
有序集合(sorted set)
- 添加(按照score排序)
zadd key score val
- 获取
zrange key start end
- 逆序获取
zrevrange key start end
- 获取结果带score
zrange key start end withscores
- 获取指定分数范围的数据
zrangebyscore key minscore maxscore
- 删除指定分数范围的数据
zremrangebyscore key startscore endscore
- 询问元素在集合中的位置
zrank key val
位图(Bitmaps)
- 添加(offset理解为而二进制的第几位数,val就是二进制中的0或1)
setbit key offset val
- 获取
getbit key offset
- 位操作
bitop [and|or|xor|not] resultkey key1 key2 key3
- 获取1的个数
bitcount key
- 获取第一个指定值(0或1)的下标
bitpos key bit start end
HyperLogLog
- 添加
pfadd key val1 val2 val3
- 统计不同元素的个数
pfcount key
- 将hll合并
pfmerge resultkey key1 key2 key3
java操作redis
- 导包
jedis-2.9.0.jar
- 代码
import redis.clients.jedis.Jedis;
public class RedisTest {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
jedis.set("hello", "world");
System.out.println(jedis.get("hello"));
}
}
spring使用redis
1.导包
jedis-2.9.0.jar
spring-data-redis-1.6.4.RELEASE.jar
2. 配置文件application-context.xml
<?xml version='1.0' encoding='UTF-8' ?>
<!-- was: <?xml version="1.0" encoding="UTF-8"?> -->
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!-- 配置连接参数JedisPoolConfig -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大空闲数 -->
<property name="maxIdle" value="50" />
<!-- 最大连接数 -->
<property name="maxTotal" value="100" />
<!-- 最大等待时间 -->
<property name="maxWaitMillis" value="20000" />
</bean>
<!-- Spring配置连接工厂JedisConnectionFactory -->
<bean id="connectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
<property name="hostName" value="localhost" />
<property name="port" value="6379" />
<property name="poolConfig" ref="poolConfig" />
</bean>
<!-- key序列化器 -->
<bean id="stringRedisSerializer"
class="org.springframework.data.redis.serializer.StringRedisSerializer" />
<!-- value序列化器 -->
<bean id="jdkSerializationRedisSerializer"
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
<!-- Redis连接池 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
<property name="connectionFactory" ref="connectionFactory" />
<property name="keySerializer" ref="stringRedisSerializer" />
<!-- 当value类型为object时使用此序列化器 -->
<property name="valueSerializer" ref="jdkSerializationRedisSerializer" />
<!-- 当value类型为string时使用此序列化器 -->
<!-- <property name="valueSerializer" ref="stringRedisSerializer" />-->
<!-- 默认 -->
<property name="defaultSerializer" ref="stringRedisSerializer" />
</bean>
</beans>
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
public class TestString {
public static void main(String[] args) {
ClassPathXmlApplicationContext app =
new ClassPathXmlApplicationContext("/db/redis/applicationContext.xml");
RedisTemplate<String, String> redisTemplate = app.getBean(RedisTemplate.class);
redisTemplate.opsForValue().set("key1", "value1");
redisTemplate.opsForValue().set("key2", "value2");
//获取
String getKey1 = redisTemplate.opsForValue().get("key1");
System.out.println(getKey1);
//字符串长度
Long size = redisTemplate.opsForValue().size("key1");
System.out.println("字符串长度:" + size);
//设置新值并返回旧值
String oldValue = redisTemplate.opsForValue().getAndSet("key1", "new_value1");
System.out.println("旧值:" + oldValue);
getKey1 = redisTemplate.opsForValue().get("key1");
System.out.println("新值:" + oldValue);
//子串
getKey1 = redisTemplate.opsForValue().get("key1", 0, 5);
System.out.println(getKey1);
//字符串拼接
redisTemplate.opsForValue().append("key1", "_app");
getKey1 = redisTemplate.opsForValue().get("key1");
System.out.println(getKey1);
app.close();
}
}
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
public class TestSpring {
public static void main(String[] args) {
ClassPathXmlApplicationContext app =
new ClassPathXmlApplicationContext("/db/redis/applicationContext.xml");
RedisTemplate redisTemplate = app.getBean(RedisTemplate.class);
//设置
Role role = new Role();
role.setRoleName("hello");
redisTemplate.opsForValue().set("r1", role);
//获取
Role getRole = (Role)redisTemplate.opsForValue().get("r1");
System.out.println(getRole);
//SessionCallback可以保证方法内所有redis语句都由同一个redis连接执行
SessionCallback<Role> sc = new SessionCallback<Role>() {
@Override
public Role execute(RedisOperations rop) throws DataAccessException {
rop.opsForValue().set("r2", role);
return (Role) rop.opsForValue().get("r2");
}
};
Role r2 = (Role) redisTemplate.execute(sc);
System.out.println(r2);
}
}
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
public class TestHash {
public static void main(String[] args) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("/db/redis/applicationContext.xml");
RedisTemplate<String, String> redisTemplate = app.getBean(RedisTemplate.class);
String KEY = "hash";
HashMap<String,String> map = new HashMap<String, String>();
map.put("sj", "88");
map.put("wj", "7floor");
//设置值
redisTemplate.opsForHash().putAll(KEY, map);
//设置单个值
redisTemplate.opsForHash().put(KEY, "student", "yxd");
//遍历所有键和值
Map<Object, Object> entries = redisTemplate.opsForHash().entries(KEY);
for (Map.Entry<Object, Object> entry : entries.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
//增加值
redisTemplate.opsForHash().increment(KEY, "sj", 2.2);
String sj = (String)redisTemplate.opsForHash().get(KEY, "sj");
System.out.println(sj);
//删除值
redisTemplate.opsForHash().delete(KEY, "student");
//遍历所有值
List<Object> values = redisTemplate.opsForHash().values(KEY);
for (Object v : values){
System.out.println(v);
}
}
}
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
public class TestHyperLogLog {
public static void main(String[] args) {
ClassPathXmlApplicationContext app =
new ClassPathXmlApplicationContext("/db/redis/applicationContext.xml");
RedisTemplate<String, String> redisTemplate = app.getBean(RedisTemplate.class);
//设置
redisTemplate.opsForHyperLogLog().add("log", "a", "b", "c", "d", "a");
redisTemplate.opsForHyperLogLog().add("log2", "a");
redisTemplate.opsForHyperLogLog().add("log2", "z");
//获取不同元素的个数
Long log = redisTemplate.opsForHyperLogLog().size("log");
Long log2 = redisTemplate.opsForHyperLogLog().size("log2");
System.out.println(log);
System.out.println(log2);
//合并
redisTemplate.opsForHyperLogLog().union("new_log", "log", "log2");
Long new_log = redisTemplate.opsForHyperLogLog().size("new_log");
System.out.println(new_log);
}
}
redis事务
watch与事务
watch:
在事务之前(multi)使用,
用法: watch key
结果: 如果观察的key的value在事务里被改变了,那么事务就会回滚
java操作事务
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
public class Tx {
public static void main(String[] args) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
RedisTemplate template = app.getBean(RedisTemplate.class);
SessionCallback callback = new SessionCallback() {
@Override
public Object execute(RedisOperations ro) throws DataAccessException {
//开启事务,创建命令队列
ro.multi();
//加入命令队列
ro.boundValueOps("k1").set("v1");
String k1 = (String) ro.boundValueOps("k1").get();
//执行命令队列的命令,有返回值
ro.exec();
// 这里只能以这种方式拿, 返回k1得到为null,为甚么
// 因为exec之前都没执行命令
return ro.boundValueOps("k1").get();
}
};
String v1 = (String) template.execute(callback);
System.out.println(v1);
}
}
流水线
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
public class RedisLine {
public static void main(String[] args) {
Jedis jedis = new Jedis();
//开启流水线
Pipeline line = jedis.pipelined();
for (int i = 0; i < 100000; i++) {
line.set("k" + i, "v" + i);
line.get("k" + i);
}
//流水线执行
line.syncAndReturnAll();
}
}
超时
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import java.util.concurrent.TimeUnit;
public class Ex {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
RedisTemplate template = app.getBean(RedisTemplate.class);
SessionCallback callback = new SessionCallback() {
@Override
public Object execute(RedisOperations ro) throws DataAccessException {
ro.boundValueOps("rg1").set("value rg1");
// 10秒的存活时间
Boolean succeedSetExpire = ro.expire("rg1", 10, TimeUnit.SECONDS);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获取剩余时间
Long expireTime = ro.getExpire("rg1");
System.out.println(expireTime);
//持久化,把过期时间去掉
Boolean isSucceedPersist = ro.persist("rg1");
//获取剩余时间, -1代表永久
expireTime = ro.getExpire("rg1");
System.out.println(expireTime);
return null;
}
};
template.execute(callback);
}
}
redis主从复制
从机只能读数据, 主机能读能写
- 重命名,复制两份配置文件改名, slave01.conf, slave02.conf
- 修改配置文件内容的port和slaveof
例如
port 6380
slaveof localhost 6379 - 根据配置文件启动redis服务
./redis-server 配置文件