reids笔记(1)

redis是一个高性能的key-value数据库,也是NOSQL数据库,是为了解决高并发,高扩展,大数据存储等问题而产生的数据库解决方案,是一个非关系型数据库,并且Redis是基于内存的单线程数据库(6.0之后支持多线程)。

redis支持数据结构类型包括:字符串,链表,哈希表,集合,有序集合等。为了保证读取的效率redis把数据对象都存储在内存中,它可以支持周期性的把更新的数据写入磁盘文件中,而且他还提供了交集和并集,以及一些不同方式排序的操作

1.NoSql优点

  1.对数据库高并发读写需求
  2.对海量数据的高效率存储和访问
  3.对数据库的高扩展性和高可用性的需求

2.主要的NoSql数据库分类

分类
数据库
应用场景
数据类型
优点
缺点
键值
(key-value)
Redis,Tokyo,
Oracle BDB
内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统
Kye指向Value的键值对,通常用hash table来实现
查询速度快
数据无结构化,通常只被当作字符串或二进制数据
列表存储
Cassandra,HBase,Riak
分布式文件系统
以列簇式存储,将同一列数据存在一起
查询速度快,可扩展性强,更容易进行分布式扩展
功能相对局限
文档型数据库
CouchDB,
MongoDB
web应用(与key-value类似,value是结构化的不同的是数据库可以了解value的内容)
key-value对应的键值对,Value为结构化数据
数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构
查询性能不高,而且缺乏统一性的查询语法
图形数据库
Neo4J,InfoGrid,Infinite Graph
社交网络,推荐系统等。专注于构件关系图谱
图结构
利用图结构相关算法,比如最短路径寻址,N度关系查找等
很多时候需要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群方案

  MongoDB:

    MongoDB数据库是一个基于分布式文件存储的数据库,C++编写,主要来处理大量的文档,MongoDB是一个介于关系型数据库和非关系型数据库中间的产品,MongoDB是非关系型数据库中功能最丰富,最像关系型数据库的

  图形数据库保存的是这种关系:

      

3.Redis特点

  1.redis是一个开源的使用c语言编写的 key-value数据库,并提供多种语言的AIP
 
  2.redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并在此基础上实现了master-slave(主从)同步
 
  3.主从同步:数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器
 
  4.redis是基于内存操作的,cpu不是redis性能瓶颈,redis的瓶颈是机器的内存和网络的宽带,redis可以作为数据库,缓存和消息中间件来使用

4.redis性能测试

  redis-benchmark 是一个官方自带的压力测试工具

 

 压力测试命令(在bin下执行):

  redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 1000

5 基础命令 :

涵义
命令
注释
windows连接redis
redis-cli -h 127.0.0.1 -p 6379
在bin目录运行
linux连接redis
redis-cli -p 6397
 
得到redis安装目录
config get dir
 
切换数据库
select 1
redis默认有16个数据库,默认使用第0个
查询数据库大小
dbsize
 
查询所有的key
keys *
 
清空数据库
flushall
 
清空当前数据库
flushdb
 
设置键值
set key value
 
得到值
get key
 
删除key
del key
 
移除key
move key 数据库编号
 
判断key是否存在
exists key
 
设置过期时间
expire key 时间
时间单位为秒
查询剩余时间
ttl key
 
查询key类型
type key
 
获取配置信息
CONFIG GET *
也可以使用 CONFIG GET "配置名" 得到配置信息
修改配置信息
CONFIG SET 配置名 “值”
 
 

6.redis数据类型及窗口命令 :

  1.String(字符串):
涵义
命令
注释
设置键值
setnx key val
当key存在不做任何操作
批量设置键值
mset key1 val1 key2 val2
 
批量获取值
mget key1 key2
这个操作是一个原子性操作,要么一起成功要么一起失败
组合getset
getset key val
key不存在创建,key存在覆盖原来的
追加内容
append key val
如果当前key不存在,执行新增操作
获取值长度
strLen key
 
根据key加一
incr key
 
根据key减一
decr key
 
根据key增加指定值
incrby key 10
 
根据key减少指定值
decryby key 10
 
字符串截取
getrange key 开始位置 结束位置
下标从0开始,结束位置-1为最后
替换字符串
setrange key 替换的位置 替换的值
原字符串:aabbcc 从1替换值 xx
结果: axxbcc
设置key及过期时间
setex key 过期时间 值
 
  
    mset和mget拓展思路用法:
  
//设置值
mset user:name 张三 user:age 18
//获取值
mget user:name user:age
//得到结果:
          张三
          18

这个样设置key向设置对象一样,方便查询和管理        
  2.hashes(散列):

     hashes散列存储的值为map集合,效果:key val(val为map集合)
     hashes散列的命令开头都是H
涵义
命令
注释
添加
Hset key key val
 
获取
Hget key key
 
添加多个
Hmset key key val key2 val2
 
获取所有的值
Hgetall key
 
获取长度
Hlen key
 
判断key是否存在
Hexists key key
 
获取所有的key
Hkeys key
 
获取所有的val
Hvals key
 
 
  3.lists(列表):
    list命令都是L开头
  
涵义
命令
注释
首部添加值
Lpush key val
例子:Lpush a one
Lpush a two
尾部添加值
Rpush key val
 
获取
Lrange key 开始下标 结束下标
下标从0开始,结束位置为-1拿全部,先入后出
删除数据
Lpop key 删除左边第一个
Rpop key 删除右边第一个
 
根据下标获取值
Lindex key 下标
 
获取列表长度
Llen key
 
移除指定值
Lrem key 移除个数 值
因为list是可重复的
截取指定范围内的值
Ltrim key 前下标 后下标
截取后list只剩那几个值了
移除列表最后一个元素,移动到新列表中
RpopLpush key1 key2
将key1的最后一个值移动到key2n内
替换值
Lset key 位置 替换的值
位置不存在会报错
在指定位置插入
Linsert key 位置 原值 插入值
原值是在哪插
    
list在指定位置插入语句实例: 
Jedis jedis = new Jedis("127.0.0.1",6379);

jedis.lpush("a","值1","值2","值3");

List<String> a = jedis.lrange("a", 0, -1);

for (String s:a){
   System.out.println(s);
}

System.out.println("插入");
//在指定的位置插入
jedis.linsert("a", ListPosition.BEFORE,"值2","值5");

List<String> b = jedis.lrange("a", 0, -1);

for (String s:b){
    System.out.println(s);
}

List小结:

  list实际上是一个链表,before Node after(前后) ,left , right 都可以插入

  如果key不存在,创建新的链表

  如果key存在,新增内容

  如果移除了所有的值,空链表,也代表不存在

  两边插入修改的效率最高,中间元素相对效率低
 

  4.set(集合)

涵义
命令
注释
添加
Sadd key val
 
查询
Smembers key
 
判断值是否存在
Sismember key val
 
获取set大小
Scard key
 
删除值
Srem key val
 
随机获取值
Srandmember key
 
获取指定数量的随机值
Srandmember key 数量
 
删除随机的key
Spop key
 
将一个指定的值移动到另一个集合
Smove 原key 目标key 移动val
 
获取差集
Sdiff key1 key2
 
获取交集
Sinter key1 key2
 
获取并集
Sunlon key1 key2
 

  5.zset(有序集合):

    zset是在set的基础上增加了一个排序值,zset k1 排序值 v1 

涵义
命令
注释
新增
Zadd key 排序 val
 
排序从小到大
ZrangeBySecore key -inf +inf
-inf负无穷,+正无穷
排序从大到小
Zrevrange key 0 -1
 
查询
Zrange key
 
移除
Zrem key val
 
获取集合长度
Zcard key
 
获取指定区间的数量
Zcount key 1 3
 

  6.geospatial(地理位置):

    可以推算地理位置信息,两地之间的距离,方圆几里的人

涵义
命令
注释
添加位置
Geoadd key 经度 纬度 城市名称 经度 纬度 城市名称
两极无法添加
获取指定城市经纬度
Geopos key 城市名
 
获取两点之间直线距离
Geodist key 城市1 城市2 距离单位
距离单位:
m : 米
km : 千米
mi : 英里
ft: 英尺
获取附近位置
Georadius key 经度 纬度 半径 距离单位
 
获取指定个数的数据
Geradius key 经度 纬度 半径 距离单位 withdist withcoord count 数量
例子:
Ceoradius key 100 30 200 km withdist withcoord count 2
 
找出指定位置的数据
GeoradiusByMember key 城市名 半径 距离单位
 
根据key和城市名获取kash值
geohash key 城市名 城市名
将二维的经纬度转换为一维的字符串,如果两个字符串越近那么距离越近

    Geo底层实现原理为zset可以使用zset命令操作Geo的值

  7.HyperLogLog:

    基数不重复的元素

涵义
命令
注释
新增
PFadd key val
 
统计(忽略重复数据)
PFcount key
 
合并
PFmerge 新key 被合并key1 被合并key2
 

        问题:

          一个人访问一个网站多次但是还是算一个人

       传统解决:

          set集合保存用户id,然后就可以统计set中的元素数量来做判断,但是这个方式如果保存大量的用户id会比较麻烦

       用HyperLogLog解决:

          优点:

            占用的内存是固定的,2^64不同的元素技术,只需要用12kb的内存

          缺点: 

            有0.81%的错误率

  8.BitMaps(位存储):

     BitMaps位图数据结构,都是操作二进制位来进行记录,就只有0和1两个状态

涵义
命令
注释
添加
setbit key 位 值
例子:
setbit key 1 a
获取值
setbit key 位
 
统计
bitcount key
 

7.redis事务 :

  1.Redis单条命令是保证原子性的,但是事务不保证原子性,Redis事务本质就是一组命令的集合,在事务执行过程中会按照顺序执行
  2.Redis事务没有隔离级别的概念,所有的命令在事务中,并没有直接执行,只有发起执行命令的时候才会执行
  
  事务命令:
    开启事务:Multi
    命令队列:需要执行的命令
    执行事务:exec
multi
set key val
set key1 val2
get key
exec
执行后会输出结果

    取消事务:discard

multi
set key val
set key1 val2
get key
discard

事务队列内的东西都不会执行

当redis内有编译异常时所有操作都不会成功,但是当有运行时异常只有报异常的那个命令不会成功

  监控:

    悲观锁:

      很悲观,感觉什么时候都会出问题,无论做什么都会加锁

    乐观锁:

      很乐观,感觉什么时候都不会出问题,无论什么时候都不加锁。

    更新的时候去判断一下在此期间是否有人修改过这条数据。

  加锁:watch key 

set qian 100

用户一:
watch qian
mulit
set qian 200

//在这个时候用户二先执行了

exec 执行事务;这个时候会执行失败,因为乐观锁会去对比版本号,版本号对应不上所以执行失败,执行失败后乐观锁会自动解锁

用户二;
set qian 10

  解锁:unwatch

8.Jedis :

   Jedis是redis官方推荐的连接java连接Redis的中间件
  
  1.引入依赖
    <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
    </dependency>

  2.事务操作

Jedis jedis = new Jedis("127.0.0.1",6379);
Transaction multi = jedis.multi();
multi.set("测试的值","测试的值");
multi.exec();

其他的操作和命令是一样的

9.SpringBoot整合Redis:

   在SpringBoot2.x之后链接redis使用的是lettuce,因为jedis采用的是直连,多个线程操作的话是不安全的,如果想要避免线程不安全需要使用jedis线程池,而lettuce采用netty实例可以在多个线程中进行共享,不存在线程不安全的情况。
     
    1.引入依赖
     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
     </dependency>

    2.application配置

spring.redis.host=127.0.0.1 
spring.redis.port=6379    
spring.redis.database=0

    3.注入redisTemplate

@Autowired
private ReisTemplate redisTemplate;

//操作不同的数据类型:
//操作字符串:redisTemplate.opsForValue() 
//操作list:redisTemplate.opsForList()
//操作set:redisTemplate.opsForSet()
//操作Hash:redisTemplate.opsForHash()
//操作ZSet:redisTemplate.opsForZSet()
//操作Geo:redisTemplate.opsForGeo()
//操作HyperLogLog:redisTemplate.opsForHyperLogLog()      

//获取redis连接对象:
RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
//清除数据库内容
connection.flushDb();

    4.解决redis中文乱码问题

              

            因为redis默认使用jdk序列化,所以会导致中文乱码,所以需要我们自己来配置
            
 
 
  5.定义自己的RedisTemplate
    (1)序列化类型
                   
  
    (2)配置RedisConfig类
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<String, Object> template = new RedisTemplate<>();

        //配置参数序列化方式
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);

        //对json进行转译
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)
        jackson2JsonRedisSerializer.setObjectMapper(om);

        template.setKeySerializer(jackson2JsonRedisSerializer);

        //String序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        //设置key采用String方式序列化
        template.setKeySerializer(stringRedisSerializer);
        //设置hash的key采用String方式序列化
        template.setHashKeySerializer(stringRedisSerializer);
        //设置value采用json序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //设置hash的val采用json序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        
        template.afterPropertiesSet();

        //设置连接工厂
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

原文地址:https://www.cnblogs.com/HQ0422/p/10719254.html