ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

Redis_自己根据尚硅谷的视频理解

2021-06-17 16:29:26  阅读:112  来源: 互联网

标签:视频 事务 Redis redis value 命令 key 硅谷


Redis

一、Redis概述

1.概念:是用C语言开发的一个开源的高性能基于内存运行的键值对NoSQL数据库。

2.特征:
①支持数据的持久化,可以将数据保存在磁盘中,重启后可以再次加载到内存中使用。
②支持多种数据类型,除了支持KV类型数据的类型,还支持list、set、hash等数据结构。
③支持master-slave模式的数据备份。

二、应用场景

1.热点数据加速查询(主要场景),如热点商品、热点信息等访问量较高的数据
2.即时信息查询,如公交到站信息、在线人数信息等
3.时效性信息控制,如验证码控制、投票控制等
4.分布式数据共享,如分布式集群架构中的session分离消息队列

三、Redis的下载和安装

去官网下载redis-3.0.4.tar.gz安装包,并放入Linux中的/opt目录
在/opt目录下,执行解压命令tar -zxvf redis-3.0.4.tar.gz
解压完成后出现文件夹redis-3.0.4
进入文件夹redis-3.0.4,在此目录下执行make && make install命令
进入默认安装目录cd /usr/local/bin,此目录中有如下文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SFuyHOvs-1623918085970)(C:\Users\刘星\AppData\Roaming\Typora\typora-user-images\image-20210609152012166.png)]

四、Redis服务的启动

查看redis的进程:
ps -ef |grep redis

1.修改redis配置文件,vim /opt/redis-3.0.4/redis.conf

在这里插入图片描述

2.启动redis服务,cd /usr/local/bin,执行redis-server /opt/redis-3.0.4/redis.conf
3.查看服务是否启动,ps aux | grep redis-server

在这里插入图片描述

五、Redis命令行工具

redis-cli -p 6379 :使用redis命令行工具
ping :测试是否连通
set k1 v1 :存放键值对
get k1 :取出键值对
shutdown :关闭Redis服务
exit

在这里插入图片描述

六、Redis基础知识

1.Redis采用单线程机制进行工作。
2.Redis默认拥有16个数据库,数据库编号从0开始,默认使用0号数据库。
3.使用select 数据库编号 可以切换使用的数据库。
4.dbsize 命令查看当前数据库key的数量。
5.keys * 命令查看当前数据库所有的key。
6.flushdb 命令清空当前数据库。
7.flushall 命令清空所有数据库。
8.Redis中所有数据库使用同一个密码,默认没有密码,Redis认为安全层面应该由Linux来保证。
9.Redis中所有索引都是从0开始。
10.Redis默认端口是6379。

七、Redis数据类型

1.Key(键)

常用命令:
①DEL key :该命令用于在Key存在时删除key。
②EXISTS key:检查给定key是否存在。
③EXPIRE key seconds :给指定key设置过期时间,以秒计。
④MOVE key db :将当前数据库中的key移动到指定的数据库中。
⑤TTL key :以秒为单位,返回给定key的剩余生存时间。
⑥TYPE key :返回key所存储的值的类型。

Redis有五大数据类型:String、List、Set、Zset、Hash。
注:Redis采用键值对存储数据,key永远时String类型,五大数据类型指定的value。

2.String(字符串)

一个key对应一个value;String可以包含任何数据,String是Redis最基本的数据类型,一个String的value最大可支持512M。

常用命令:
①set key value : 设置指定key的值。
②get key :获取指定key的值。
③getrange key start end :返回key中字符串值的子字符。
④getset key value :将给定key的值设为value,并返回key的旧值,
⑤mget key1 [key2…] :获取所有(一个或多个)给定key的值。
⑥setex key seconds value :将值value关联到key,并将key的过期使劲按设置为seconds秒。
⑦setnx key value :只有在key不存在时设置key的值
⑧setrange key offset value : 用value参数覆写给定key所存储的字符串值,从偏移量offset开始。
⑨setlen key :返回key所存储的字符串值的长度。
⑩mset key value [key value …] :同时设置一个或者多个key-value对。
msetnx key value [key value …] :同时设置一个或者多个key-value对,当且仅当多有给定key都不存在时。
incr key :将key中的存储的数字值增加一。
decr key :将key所存储的数字值减一。
incrby key increment : 将key所存储的值加上给定的增量值(increment)
decrby key decrement : key所存储的值减去给定的值(decrement)
append key value : 如果key已经存在并且时一个字符串,append命令将给定的value追加到该key原来之(value)的末尾。

3.List(列表)

底层时一个字符串链表,可以从头或尾加入元素。

​ 注:(1)添加元素时:
​ 如果key不存在,创建新的链表
​ 如果key已存在,添加内容
​ 如果key的所有值全部删除,则对应的key也会随之消失

​ (2)在链表的头尾为操作时效率较高,但是对中间元素的操作效率较低。

常用命令:
lindex key index : 通过索引过去列表中的元素。
llen key : 获取列表长度。
lpop key : 移除并过去列表的第一个元素。
rpop key :一处列表的最后一个元素,返回值为移除的元素。
lpush key value [value …] :创建一个列表,存储顺序是在前面的值存储在最下面(类似于栈,先进后出)
rpush key value [value …] :创建一个列表,存储顺序是在最前面的值存储在最前面。
lrange key start stop : 获取李彪指定范围内的元素。
linsert key before | after pivot value :在列表的元素前或者后插入元素 (pivot为列表中已存在的值,value为要插入的值)
lrem key count value : 从左往右删除sount哥value值,count为0表示删除全部给定的值。
lset key index value : 通过索引设置列表元素的值。
ltrim key start stop : 对一个列表进行修建,让列表保存指定区间内的元素,不在指定区间之内的元素都将被删除。
rpoplpush source destination : 移除列表的最后一个元素,并将给元素添加到另一个列表头部并返回。

4.Set(集合)

底层是通过HashTable实现,是String类型的无重复值的无序集合。

常用命令:
sadd key member1 [member2 …] :向集合中添加一个或者多个成员。
smembers key : 获取集合中所有元素。
sismember key value : 判断value是否存在于key中。
scard key : 获取集合的成员数。
srem key value : 删除集合中的元素。
srandmember key 数字 : 随机出几个数。
spop key :随机出栈。
smove key1 key2 在key1里某个值 : 作用是将key1里的某个值赋给key2。
sdiff key1 key2 : 差集。
sinter key1 key2 : 交集。
sunion key1 key2 : 并集。

5.Hash(哈希)

类似Java中的Map<String, Object>;是一个键值对集合;适合存储对象。

常用命令:
hset key filed value : 将哈希表key中的字段filedd 值设为value。
hget key field : 获取存储在哈希表中指定字段的值。
hmset key filed value [filed value …] : 设置哈希表key的多个字段和值。
hmget key filed [filed …] : 获取存储在哈希表key中一个或多个字段指定的值。
hgetall key : 获取存储在哈希表key中所有字段和字段指定的值。
hdel key filed [filed …] : 删除一个或多个哈希表字段。
hlen key :获取哈希表key的长度。
hexists key filed :判断在哈希表key中是否存在filed这个字段。
hkeys key :获取哈希表key中的所有的字段。
hvals key :获取哈希表key中的所有的字段的值。
hincrby key filed increment : 为哈希表key中的指定字段的整数值加上增量increment。
hincrbyfloat key filed increment : 为哈希表key中的指定字段的浮点数值加上增量increment。
hsetnx key filed value : 只有在字段filed不存在时,设置哈希表字段的值。

6.ZSet(有序集合)

类似Set;每个元素都会关联一个double类型的分数(score);Redis通过分数自动的为集合中的 成员进行从小到大的排序;成员不可重复,分数可以重复。

常用命令:
zadd key score1 member1 [score2 member2…] : 像有序集合添加一个或多个成员,或者更新已存在成员的分数。
zrange key start stop [withscores] : 通过索引区间返回有序区间指定区间内的成员,[是否需要带参数]。
zrangebyscore key min max [withscores] [limit offset count ] : 通过分数返回有序集合指定区间内的成员。min最小分数,max最大分数,limit 限制,offset 索引 , count 个数。
zrem key member [member…] : 移除有序集合一个或者多个成员。member是value值。
zcard key : 获取有序集合的成员数。
zcount key min max : 计算在有序集合中指定分数区间分数的成员数。
zrank key value :获取value的下标值。
zscore key member : 获取指定member是score值。
zrevrank key value : 通过逆序过去下标值。
zrevrange key start stop [withscores] : 指定区间,通过索引逆向输出成员,是否需要代参数。

八、Redis的持久化

持久化该概念:

意外断电或重启之后,内存中的数据将会丢失,故应当将内存中的数据保存在磁盘中。

概念:
利用磁盘等将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化

持久化的两种方式
快照:
将某个时间点的工作状态保存下来,恢复时可直接恢复指定时间点的工作状态Redis中这种方式称为RDB

日志:
将对数据的所有操作过程记录下来,恢复数据时重新执行这些操作Redis中这种方式称为AOF

1.rdb(Redis Database)

①概念:在指定的时间间隔内将内存中的数据集快照写入磁盘。
也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
rdb是什么:
Redis会单独创建(fork) 一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点最后一次持久化后的数据可能丢失。

②Fork:
Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)。
数值都和原进程一致,但是一个全新的进程,并作为原进程的子进程。

③Rdb保存的是dump.rdb文件:
可以修改内存中数据保存的文件的名称,默认值为dump.rdb。
在这里插入图片描述

修改rdb文件保存的目录

在这里插入图片描述

SNAPSHOTTING快照:
Save:执行save指令即可将内存中的数据保存到dump rdb文件中。
Redis是单线程的,故执行save指令会阻塞其之后的命令的执行(可能多人操作同一个Redis 服务器),如果要保存的数据较多时,会导致之后的命令长时间阻塞,故一般不使用save指令。
Stop-writes-on-bgsave-error:如果配置成no,表示你不在乎数据不一致或者有其他的手段发现和控制。默认yes。
rdbcompression:对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能。默认yes。
rdbchecksum:在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。

⑤如何触发RDB快照:
冷拷贝后重新使用。
命令save或是bgsave:
save:只管保存,其他不管,全部阻塞。
bgsave:Redis会在后台进行快照操作,快照同时还可以相应客户端请求。可以通过lastsave命令获取最后一次成功执行快照的时间。指令可以让保存操作在后台执行,让redis服务可以继续执行其之后的指令,使用较多。

⑥如何恢复:
将备份文件(dump.rdb)移动到redis安装且录并启动服务即可。
CONFIG GET dir获取目录
⑦优势:
适合大规模的数据恢复
对数据完整性和一致性要求不高

⑧劣势:
在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。
Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑。
基于快照思想,每次读写都是全部数据,效率低。

⑨如何停止:
动态所有停止RDB保存规则的方法: redis-cli config set save “”

2.aof(Append Only File)

①概念:以日志的形式来记录每个写操作,将Redis执行过的所有写命令记录下俩(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据。

②Aof保存的是appendonly.aof文件:

③配置文件redis.config:

image-20210613235616064

Appendfsync:
Always:同步持久化每次发生数据变更会被立即记录到磁盘性能较差但数据完整性比较好
Everysec: 出厂默认推荐,异步操作,每秒记录 如果1秒内宕机,有数据丢失
No
No-appendfsync-on-rewrite:重写时是否可以运用Appendfsync,用默认no即可,保证数据安全性。
Auto-aof-rewrite-min-size:设置重写的基准值
Auto-aof-rewrite-percentage:设置重写的基准值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DLhfuYjm-1623918085976)(C:\Users\刘星\AppData\Roaming\Typora\typora-user-images\image-20210614001218107.png)]

④Rewrite:AOF文件中已经记录的对同一数据的若干条操作的记录转换为数据最终结果对应指令的记录。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hVDWnpoT-1623918085978)(C:\Users\刘星\AppData\Roaming\Typora\typora-user-images\image-20210614000515294.png)]
AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。可以使用命令bgrewriteaof
重写原理:AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。
触发机制:Redis会记录上次重写时的A0F大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。

⑤Aof启动/修复/恢复:
当appendonly.aof文件内被恶意修改,使用命令:
redis-check-aof --fix appendonly.aof

⑥优势:
每秒同步: appendfsync always同步持久化 每次发生数据变更会被立即记录到磁盘性能较差但数据完整性比较高。
每修改同步: appendfsync everysec 异步操作,每秒记录,如果1秒内宕机,有数据丢失
不同步:annendfevnc no 从不同步

⑦劣势:
相同数据集的数据而言aof文件远大于rdb文件,恢复速度慢于rdb
Aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同
image-20210614002332608

只做缓存:只希望数据在服务器运行的时候存在,可以不使用任何持久化方式
建议同时开启两种持久化方式:

九、Redis事务

1.redis事务的概念

可以一次执行多个命令,本质是一组命令的集合。一个事务中的
所有命令都会序列化,按顺序地串行化执行,执行而不会被其它命令插入,不许加塞。

一个队列中,一次性、顺序性、排他性的执行一系列命令。

2.redis事务命令及描述

DISCARD:取消事务,放弃执行事务块内的所有命令。
EXEC:执行所有事务块内的命令。
MULTI:标记一个事务块的开始
UNWATCH:取消WATCH命令对所有key的监视。
WATCH key [key …] :监视一个(或多个) key , 如果在事务执行之前这个(或这些) key被其他命令所改动,那么事务将被打断。

情况:
正常执行
放弃事务
全体连坐:当事务出现语法错误时(命令错误时),事务不会提交
冤头债主:当事务出现运行时异常,事务会提交,错误的一条命令将会报错,但命令会执行。
watch监控:

​ 悲观锁(Pessimistic Lock):顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上 锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读 锁,写锁等,都是在做操作之前先上锁。

​ 乐观锁(Optimistic Lock):顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时
​ 候会判断一下 在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量

​ 乐观锁策略:提交版本必须大于记录当前版本才能执行更新。推荐使用乐观锁。

​ 无加塞篡改,**先监控再开启multi,**保证两笔金额变动在同一个事务内。

3.总结:

​ Watch指令,类似乐观锁,事务提交时,如果Key的值已被别的客户端改变,
​ 比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行
​ 通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,
​ EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败

4.执行阶段:

​ 开启:以MULTI开始一个事务(先监控再开启multi)
​ 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面|
​ 执行:由EXEC命令触发事务

三个特性:

​ 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
​ 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,
​ 也就不存在"事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题
​ 不保证原子性: redis同一个事 务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚

十、Redis消息订阅发布简介(了解)

1、概念

进程间的一-种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

2、命令

PSUBSCRIBE pattem [pattem …] :订阅一个或多个符合给定模式的频道。
PUBSUB subcommand [argument [argument …]] : 查看订阅与发布系统状态。
PUBLISH channel message:将信息发送到指定的频道。
PUNSUBSCRIBE Ipattem [pattem …]]:退订所有给定模式的频道。
SUBSCRIBE channel [channel ]:订阅给定的一个或多个频道的信息。
UNSUBSCRIBE [channel [channel …]] :指退订给定的频道。

十一、主从复制

1.概念:

主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制, Master以写为主,Slave以读为主。

2.能做什么:

读写分离
容灾恢复

master可写可查,slave只能查。

3.用法:

1.配从(库)不配主(库)

2.从库配置:

slaveof 主库IP 主库端口

每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件
Info replication:查看主库或从库信息。

3.修改配置文件的细节操作:

​ 1.拷贝多个redis.conf文件圍
​ 2.开启daemonize yes
​ 3.Pid文件名字
​ 4.指定端口
​ 5.Log文件名字
​ 6.Dump.rdb名字

4.常用招数

1.一主二仆:在两个库中输入:slaveof 主库IP 主库端口。

主库突然down掉,从库不会上位,主库恢复后,主库会回位。
从库down掉,需要重新连接,除非你配置进redis.conf文件。

2.薪火相传

上一个Slave可以是“下一个slave的Master,Slave同 样可以接收其他
slaves的连接和同步请求,那么该slave作为了链条中下一个的master,
可以有效减轻master的写压力
中途变更转向:会清除之前的数据\重新建立拷贝最新的
Slaveof 新主库IP 新主库端口

3.反客为主

SLAVEOF no one :使当前数据库停止与其他数据库的同步,转成主数据库

4复制原理

Slave启动成功连接到master后会发送一个sync命令|
Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,
在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步
全量复制:而slave服 务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步
但是只要是重新连接master,-次完全同步(全量复制)将被自动执行

5.哨兵模式

当主机宕机后,从机会投票选出新主机接替成为主机。

1.使用步骤:自定义的/myredis目录下新建sentinel.conf文件,名字绝不能错
配置哨兵,填写内容:sentinel monitor被监控数据库名字(自己起名字) 127.0.0.1 6379 1
上面最后一个数字1,表示主机挂掉后salve投票看让谁接替成为主机,得票数多少后成为主机
Redis-sentinel /usr/common/sentinel.conf
启动哨兵:Redis-sentinel /usr/sentinel.conf
上述目录依照各自的实际情况配置,可能目录不同
正常主从演示
原有的master挂了
投票新选
重新主从继续开工,info replication查看
如果之前的master重启回来,不会双master冲突,原有的master将变成slave。

2.一组sentinel能同时监控多个Master

6.复制的缺点

由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定 的延迟,当系统很繁
忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。

十二、Jedis

DENIED Redis is running in protected mode报错解决办法

设置protected-mode noimg
就可连接redis
Jedis jedis=new Jedis(“192.168.128.13”,6379);

常用API:

jedis.keys("*");

jedis.mset(“k11”,“v11”,“k22”,“v22”,“k33”,“v33”,“k44”,“v44”);

jedis.lpush(“list”,“1”,“2”,“3”,“4”,“5”);

jedis.hset(“hash01”,“name”,“liuxing”);
jedis.hset(“hash01”,“id”,“2018211376”);

jedis事务

日常:
Transaction transaction=jedis.multi(); //开启事务
transaction.set(“k4”,“v4”);
transaction.set(“k5”,“v5”);
transaction.exec(); //提交事务
transaction.discard(); //取消事务提交

加锁:
jedis.watch(); //开启监控,例如:jedis.watch(“balance”):
jedis.unwatch(); //放弃监控

JedisPool

src目录下创建redis.properties配置文件

#最大连接数
redis.maxTotal=50
#默认开启的活跃连接数
redis.maxIdel=10
#Linux的ip地址
redis.host=192.168.200.130
#redis的端口号
redis.port=6379

创建Jedis的工具类JedisUtils

public class JedisUtils {
// 将从配置文件读取的配置信息赋予如下变量
private static int maxTotal;
private static int maxIdel;
private static String host;
private static int port; // 端口号为int类型

// Jedis的连接池配置
private static JedisPoolConfig jedisPoolConfig;

// Jedis连接池
private static JedisPool jedisPool;

static {
    // 读取redis.properties配置文件
    ResourceBundle bundle = ResourceBundle.getBundle("redis");
    maxTotal = Integer.parseInt(bundle.getString("redis.maxTotal"));
    maxIdel = Integer.parseInt(bundle.getString("redis.maxIdel"));
    host = bundle.getString("redis.host");
    port = Integer.parseInt(bundle.getString("redis.port"));

    // Jedis连接池配置
    jedisPoolConfig = new JedisPoolConfig();
    jedisPoolConfig.setMaxTotal(maxTotal);
    jedisPoolConfig.setMaxIdle(maxIdel);
    jedisPool = new JedisPool(jedisPoolConfig, host, port);
}

public static Jedis getJedis() {
    return jedisPool.getResource();
}
}

创建测试类JedisTest

public class JedisTest {
    public static void main(String[] args) {
        // 1. 获取Jedis对象
        Jedis jedis = JedisUtils.getJedis();

        // 2. 执行操作,Jedis中操作的方法名与Linux中命令行工具中的指令同名
        jedis.sadd("key1", "abc", "abc", "def");
        Long key1 = jedis.scard("key1");
        System.out.println("运行结果:" + key1);

        // 3.关闭连接
        jedis.close();
    }
}

标签:视频,事务,Redis,redis,value,命令,key,硅谷
来源: https://blog.csdn.net/qinchengmei/article/details/117996293

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有