docker安装redis
docker pull redis
docker run -itd --name redis -p 6379:6379 -v /home/admin/redis/redis.conf:/etc/redis/redis.conf -v /home/admin/redis/data:/data redis redis-server /etc/redis/redis.conf
docker安装完redis后内部是没有配置文件的,需要在创建之前指定
下面命令是让redis加载所给的配置文件
redis-server /etc/redis/redis.conf
redis.conf内容见附录
- 进入redis容器,并进行相关操作
docker exec -it redis bash
- 输入redis-cli,进入redis命令行
- redis-cli中使用中文的值可能会有乱码
使用以下命令进入可以避免
redis-cli --raw
常用命令
- 切换数据库
数据库默认从0~15
- select num
select 3
- 查看数据库数据大小
- dbsize
dbsize
- 查看所有的键
- keys *
keys *
- 清空当前数据库
- flushdb
flushdb
- 清空全部数据库
- flushall
flushall
- 查看某个键是否存在
- exists key
exists name
- 设置某个键过期的时间
- expire key second
设置键name失效的时间为5s
expire name 5
- 查看键剩余的时间
- ttl key
ttl name
- 移动键到另一个数据库
- move key dbindex
移动name到1号数据库
move name 1
- 查看数据类型
- type key
type name
- 删除键
- del key
del name
数据类型及相关操作
- string
- list
- set
- hash
- zset(有序集合)
特殊数据类型
- geospetial(地理位置)
- hyperloglog(基数统计)
- bitmap(位运算)
string类型操作
- 设置数据
- set key value
set name zhangsan
- 查看数据
- get key
get name
- 删除键
- del key
del name
- 向字符串尾部追加数据
- append key value
append name zhangsan
- 查看数据长度
- strlen key
strlen name
- 数字字符串加1
- incr key
incr age
- 数字字符串减1
- decr key
decr age
- 数字字符串增加指定数量
- incrby key num
incrby age 10
- 数字字符串减少指定数量
- decrby key num
decrby age 5
- 截取数据
- getrange key start end
截取键name中字符串0~3位置的字符
getrange name 0 3
截取全部字符串
getrange name 0 -1
- 设置字符串中某位置开始的数据
- setrange key index string
设置name数据中从1位置开始的数据为abc
setrange name 1 abc
- 设置键值同时指定过期时间
- setex key second value
setex name 5 zhangsan
- 键值不存在再设置键值
- setnx key value
如果name存在则不设置,否则设置键name的值为zhangsan
setnx name zhangsan
- 批量设置键值
- mset key value …
mset k1 v1 k2 v2 k3 v3
- 批量获取值
- mget key1 key2 …
mget k1 k2 k3
- 批量设置键值,有一个键已存在则失败
- msetnx key value …
如果k1已存在,则整个操作失败(原子性)
msetnx k1 v1 k2 abc
- 巧设键
- user:{id}:{filed}
mset user:1:name zhangsan user:1:age 4
获取值
mget user:1:name user:1:age
- 获取旧值设置新值
- getset key value
返回旧值zhagnsan,设置新值lisi,旧值不存在则为null
getset name lisi
list类型操作
- 向左插入元素
- lpush key value …
向左插入, 0位置为def
def, abc
lpush list abc
lpush list def
插入多个元素
lpush list a b c d e
- 向右插入元素
- rpush key value
向右插入, 0位置为abc
abc, def
rpush list abc
rpush list def
- 查看元素
- lrange key start stop
lrange list 0 -1
- 移除左边元素
- lpop key
lpop list
- 移除右边元素
- rpop key
rpop list
- 获取列表中某个值
- lindex key index
lindex list 0
- 获取列表长度
- llen key
llen list
- 移除列表中任意个数的值
- lrem key count value
从左开始依次移除列表3个a
lrem list 3 a
- 在原列表中截取数据
- ltrim key start stop
截取列表中0-5的数据,其余删除
ltrim list 0 5
- 移除列表最后一个元素,同时将该元素添加到新的列表中
- rpoplpush key1 key2
rpoplpush list li
- 将指定下标的值替换
- lset key index value
如果下标不存在则报错
lset list 0 abc
- 在某个值前后进行插入
- linsert key before|after pivot value
从左往右,在第一个a前面插入b
linsert list before a b
从左往右,在第一个a后面插入b
linsert list after a b
set类型操作
set内的值无序,不能重复
- 添加元素
- sadd key value …
sadd st a b c
- 查看元素
- smembers key
smembers st
- 获取集合元素的个数
- scard key
scard st
- 移除元素
- srem key member …
srem st a b c
- 随机获取任意数量元素
- srandmember key [count]
srandmember st
srandmember st 2
- 随机移除任意数量的元素
- spop key [count]
spop st 3
- 将一个集合中的元素移动到另一个集合
- smove source destination member
将集合st中的a元素移动到集合st2中
smove st st2 a
- 获取集合的差集
- sdiff key1 key2 …
找出st1数据在st2、st3…中不存在的
sdiff st1 st2
- 获取集合的交集
- sinter key1 key2 …
找出st1和st2…中共同拥有的元素
sinter st1 st2
- 获取集合的并集
- sunion key1 key2 …
sunion st1 st2
hash类型操作
- 添加数据
- hset key field value
在hash集合hs中添加一个键name,值为zhangsan
hset hs name zhangsan
- 查询数据
- hget key field
hget hs name
- 批量添加数据
- hmset key field value [field value …]
hmset hs name zhangsan age 4
- 批量查找数据
- hmget key field [field …]
hmget hs name age
- 获取某个hash集合中所有的键值
- hgetall key
hgetall hs
- 删除hash集合中的某个数据
- hdel key field [field …]
hdel hs name
- 获取hash集合中的数据个数
- hlen key
hlen hs
- 判断hash集合中的字段是否存在
- hexists key field
hexists hs name
- 只获取所有的键
- hkeys key
hkeys hs
- 只获取所有的值
- hvals key
hvals hs
- 数字增加指定值
- hincrby key field increment
num增加5
hincrby hs num 5
num减少5
hincrby hs num -5
- 存在则不添加,否则添加
- hsetnx key field value
hsetnx hs name lisi
zset类型操作
- 添加数据
- zadd key score member …
zadd zs 1 a 2 b 3 c 4 d
- 查看数据(按分数从小到大排序)
- zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
-inf, +inf 表示无穷小和无穷大
在集合zs中,寻找分数在[-∞, +∞]区间,按照从小到大排序
zrangebyscore zs -inf +inf
在集合zs中,寻找分数在[-∞, +∞]区间,按照从小到大排序, 附带分数
zrangebyscore zs -inf +inf withscores
min和max形成的区间是闭区间[min, max], 如果想要开区间(min, max)
zrangebyscore zs (1 (3 withscores
- 查看数据(按分数从大到小排序)
- zrevrangebyscore key max min [WITHSCORES] [LIMIT offset count]
zrevrangebyscore zs +inf -inf withscores limit 0 2
- 查看某一范围内数据
- zrange key start stop [WITHSCORES]
zrange zs 0 1
- 反转查看某一范围数据
- zrevrange key start stop [WITHSCORES]
zrevrange zs 0 -1
- 删除数据
- zrem key member [member …]
zrem zs a
- 获取集合元素的个数
- zcard key
zcard zs
- 获取指定区间的元素个数
- zcount key min max
zcount zs 2 3
geospetial类型操作
- 添加数据
- geoadd key longitude latitude member [longitude latitude member …]
geoadd china:city 116.405285 39.904989 beijing
geoadd china:city 121.472644 31.231706 shanghai
geoadd china:city 106.504962 29.533155 chongqing
geoadd china:city 120.153576 30.287459 hangzhou
- 获取指定城市的经纬度值
- geopos key member [member …]
geopos china:city beijing
- 获取两城市间的直线距离
- geodist key member1 member2 [unit]
unit(单位):
-
m: 米
-
km:千米
-
mi: 英里
-
ft: 英尺
geodist china:city beijing shanghai
geodist china:city beijing shanghai km
- 获取附近的城市
- georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
查看经度110,纬度30附近800km内的城市
georadius china:city 110 30 800 km
- withcoord:将位置元素的经度与纬度也一并返回
- withdist:在返回位置元素的同时,将距离也一并返回。距离的单位和用户给定的范围单位保持一致
- withhash:以52位的符号整数形式,返回位置元素经过geohash编码的有序集合分值。用于底层应用或调试,实际作用不大。
- sort取值范围
- asc:根据中心位置,按照从近到远的方式返回位置元素
- desc:根据中心位置,按照从远到近的方式返回位置元素
- store key:将返回结果而的地理位置信息保存到指定键
- storedist key:将返回结果距离中心节点的距离保存到指定键
查看经度110,纬度30附近800km内的城市, 并附带经纬度、距离,按城市距离进行从近到远排序,返回前两个
georadius china:city 110 30 8000 km withcoord withdist count 2 asc
- 获取城市的hash表示
- geohash key member [member …]
返回11个字符的字符串,将二维的经纬度转化为字符串,字符串越接近,距离越近
geohash china:city beijing shanghai
- geospetial底层基于zset,可以通过zset的相关命令操作geospetial
zrange china:city 0 -1
zrem china:city beijing
hyperloglog类型操作
- 添加数据
- pfadd key element [element …]
pfadd pf a b c d e
- 查看元素个数
- pfcount key [key …]
pfcount pf
- 合并集合
- pfmerge destkey sourcekey [sourcekey …]
将pf1和pf2中的数据合并到pf3中,去除重复的
pfmerge pf3 pf1 pf2
bitmap类型操作
- 添加数据
- setbit key offset value
setbit bm 1 0
setbit bm 2 1
setbit bm 3 1
- 获取数据
- getbit key offset
getbit bm 3
- 统计1的个数
- bitcount key [start end]
bitcount bm
事务
执行事务
redis的事务:
- 开始事务(multi)
- 命令入队
- 执行事务(exec) / 放弃事务(discard)
multi
set k1 v1
set k2 v2
set k3 v3
get k2
exec
异常
- 编译型异常(代码、命令有问题): 事务中所有的命令都不会被执行
multi
set k1
set k2 v2
exec
- 运行时异常(语法问题): 命令可以执行,错误命令抛出异常
multi
incr k1
set k2 1
incr k2
exec
监控
- 悲观锁
认为任何时候都会出问题,无论做什么都会加锁
- 乐观锁
认为任何时候都不会出问题,所以不会上锁。在更新数据的时候判断是否有人修改过这个数据
使用乐观锁测试多线程修改值
- 终端1
set money 100
set out 0
watch money
multi
decrby money 20
incrby out 20
- 终端2
multi
set money 50
exec
- 终端1
exec
此时终端1的操作会失败
watch可以当做redis的乐观锁,当使用该命令时,redis会监测数据变化情况,如果在此期间进行数据的更新,则事务操作失败。
unwatch可以进行解锁
jedis使用
环境配置
pom.xml
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.71</version>
</dependency>
基本使用
jedis的使用和命令一致
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.flushDB();
jedis.set("username", "zhangsan");
System.out.println(jedis.get("username"));
jedis.lpush("li", "1");
jedis.lpush("li", "2");
System.out.println(jedis.lrange("li", 0, -1));
事务操作
Jedis jedis = new Jedis("127.0.0.1", 6379);
JSONObject jsonObject = new JSONObject();
jsonObject.put("username", "zhangsan");
jedis.watch("user");
// 开启事务
Transaction transaction = jedis.multi();
try {
transaction.set("user", jsonObject.toJSONString());
// 执行事务
transaction.exec();
} catch (Exception e) {
// 放弃事务
transaction.discard();
e.printStackTrace();
} finally {
jedis.close();
}
System.out.println(jedis.get("user"));
Springboot集成redis
环境配置
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
application.properties
spring.redis.host=localhost
spring.redis.port=6379
基本操作
数据库操作
// 获取redis的连接对象
RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
connection.flushAll();
connection.flushDb();
不同数据类型操作
// 不同数据类型操作
redisTemplate.opsForValue();
redisTemplate.opsForList();
redisTemplate.opsForSet();
redisTemplate.opsForHash();
redisTemplate.opsForZSet();
redisTemplate.opsForGeo();
redisTemplate.opsForHyperLogLog();
自定义redisTemplate
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// String的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
redisTemplate.setKeySerializer(stringRedisSerializer);
// hash采用String的序列化方式
redisTemplate.setHashKeySerializer(RedisSerializer.string());
// value序列化采用jackson方式
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化采用jackson方式
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
RedisUtil工具类封装
@Component
public class