互聯(lián)網(wǎng)企業(yè):超詳細的Redis筆記,十分鐘搞定

Redis簡介:

Redis 是完全開源免費的,遵守 BSD 協(xié)議,是一個高性能的 key - value 數(shù)據(jù)庫。

Redis的全稱是 Remote Dictionary Server,它是一款開源的高性能的NoSQL數(shù)據(jù)庫,它可以用作數(shù)據(jù)庫、緩存消息隊列。

Redis 與 其他 key - value 緩存產(chǎn)品有以下三個特點:

  • Redis 支持?jǐn)?shù)據(jù)持久化,可以將內(nèi)存中的數(shù)據(jù)保存在磁盤中,重啟的時候可以再次加載進行使用。
  • Redis 不僅僅支持簡單的 key - value 類型的數(shù)據(jù),同時還提供 list,set,zset,hash 等數(shù)據(jù)結(jié)構(gòu)的存儲
  • Redis 支持?jǐn)?shù)據(jù)的備份,即 master - slave 模式的數(shù)據(jù)備份

Redis優(yōu)勢:

  • 性能極高 – Redis 讀的速度是 110000 次 /s, 寫的速度是 81000 次 /s 。
  • 豐富的數(shù)據(jù)類型 - Redis 支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數(shù)據(jù)類型操作。
  • 原子性 - Redis 的所有操作都是原子性的,意思就是要么成功執(zhí)行要么失敗完全不執(zhí)行。單個操作是原子性的。多個操作也支持事務(wù),即原子性,通過 MULTI 和 EXEC 指令包起來。
  • 其他特性 - Redis 還支持 publish/subscribe 通知,key 過期等特性。

NoSQL

NoSQL 最常見的解釋是 non-relational,非關(guān)系型數(shù)據(jù)庫,還有一種說法是 Not Only SQL,不僅僅是 SQL,NoSQL 僅僅是一個概念,泛指非關(guān)系型的數(shù)據(jù)庫,區(qū)別于關(guān)系數(shù)據(jù)庫,它們不保證關(guān)系數(shù)據(jù)的 ACID 特性。ACID 即

  • A (Atomicity) 原子性
  • C (Consistency) 一致性
  • I (Isolation) 獨立性
  • D (Durability) 持久性

Redis 通過提供多種鍵值對的數(shù)據(jù)類型來適應(yīng)不同場景下的存儲需求。

Redis 數(shù)據(jù)類型及主要應(yīng)用場景:

image

關(guān)于上表中的部分釋義:

  1. 壓縮列表是列表鍵和哈希鍵的底層實現(xiàn)之一。
    當(dāng)一個列表鍵只包含少量列表項,并且每個列表項要么就是小整數(shù),要么就是長度比較短的字符串,Redis就會使用壓縮列表來做列表鍵的底層實現(xiàn)
  2. 整數(shù)集合是集合鍵的底層實現(xiàn)之一,當(dāng)一個集合只包含整數(shù)值元素,并且這個集合的元素數(shù)量不多時,Redis就會使用整數(shù)集合作為集合鍵的底層實現(xiàn)
  • 字符串 - strings

string 字符串 是 Redis 中最簡單的數(shù)據(jù)類型,它是與 Memcached 一樣的類型,一個 key 對應(yīng)一個 value,這種 key/value 對應(yīng)的方式稱為鍵值對。字符串對很多例子都有用,例如緩存 HTML 片段和網(wǎng)頁。

  • 集合 - set

set 是集合,和我們數(shù)學(xué)中的集合概念相似,對集合的操作有添加刪除元素,有對多個集合求交并差等操作。操作中 key 理解為集合的名字。

  • 散列 - hash

hash 是一個鍵值 (key=>value) 對集合;是一個 string 類型的 field 和 value 的映射表,hash 特別適合用于存儲對象。

  • 列表 - list

Redis 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)。list類型經(jīng)常會被用于消息隊列的服務(wù),以完成多程序之間的消息交換。

  • 有序集合 - zset

Redis zset 和 set 一樣也是 string 類型元素的集合,且不允許重復(fù)的成員。當(dāng)你需要一個有序的并且不重復(fù)的集合列表時,那么可以選擇 sorted set 數(shù)據(jù)結(jié)構(gòu)。

應(yīng)用場景:

Redis 的應(yīng)用場景包括:緩存系統(tǒng)(“熱點”數(shù)據(jù):高頻讀、低頻寫)、計數(shù)器、消息隊列系統(tǒng)、排行榜、社交網(wǎng)絡(luò)和實時系統(tǒng)。

[圖片上傳失敗...(image-2d6283-1606379864088)]

Redis常用命令

常用管理命令

1、啟動Redis

> redis-server [--port 6379]

如果命令參數(shù)過多,建議通過配置文件來啟動Redis。

> redis-server [xx/xx/redis.conf]

6379是Redis默認端口號。

2、連接Redis

> ./redis-cli [-h 127.0.0.1 -p 6379]

3、停止Redis

> redis-cli shutdown

> kill redis-pid

以上兩條停止Redis命令效果一樣。

4、發(fā)送命令

給Redis發(fā)送命令有兩種方式:

1、redis-cli帶參數(shù)運行,如:

> redis-cli shutdown
not connected> 

這樣默認是發(fā)送到本地的6379端口。

2、redis-cli不帶參數(shù)運行,如:

> ./redis-cli

127.0.0.1:6379> shutdown
not connected> 

5、測試連通性

127.0.0.1:6379> ping
PONG

key操作命令

獲取所有鍵

語法:keys pattern

127.0.0.1:6379> keys *
1) "javastack"

  • *表示通配符,表示任意字符,會遍歷所有鍵顯示所有的鍵列表,時間復(fù)雜度O(n),在生產(chǎn)環(huán)境不建議使用。

獲取鍵總數(shù)

語法:dbsize

127.0.0.1:6379> dbsize
(integer) 6

獲取鍵總數(shù)時不會遍歷所有的鍵,直接獲取內(nèi)部變量,時間復(fù)雜度O(1)。

查詢鍵是否存在

語法:exists key [key …]

127.0.0.1:6379> exists javastack java
(integer) 2

查詢查詢多個,返回存在的個數(shù)。

刪除鍵

語法:del key [key …]

127.0.0.1:6379> del java javastack
(integer) 1

可以刪除多個,返回刪除成功的個數(shù)。

查詢鍵類型

語法: type key

127.0.0.1:6379> type javastack
string

移動鍵

語法:move key db

如把javastack移到2號數(shù)據(jù)庫。

127.0.0.1:6379> move javastack 2
(integer) 1
127.0.0.1:6379> select 2
OK
127.0.0.1:6379[2]> keys *
1) "javastack"

查詢key的生命周期(秒)

秒語法:ttl key
毫秒語法:pttl key

127.0.0.1:6379[2]> ttl javastack
(integer) -1

-1:永遠不過期。

設(shè)置過期時間

秒語法:expire key seconds
毫秒語法:pexpire key milliseconds

127.0.0.1:6379[2]> expire javastack 60
(integer) 1
127.0.0.1:6379[2]> ttl javastack
(integer) 55

設(shè)置永不過期

語法:persist key

127.0.0.1:6379[2]> persist javastack
(integer) 1

更改鍵名稱

語法:rename key newkey

127.0.0.1:6379[2]> rename javastack javastack123
OK

字符串操作命令

字符串是Redis中最基本的數(shù)據(jù)類型,單個數(shù)據(jù)能存儲的最大空間是512M。

存放鍵值

語法:set key value [EX seconds] [PX milliseconds] [NX|XX]

nx:如果key不存在則建立,xx:如果key存在則修改其值,也可以直接使用setnx/setex命令。

127.0.0.1:6379> set javastack 666
OK

獲取鍵值

語法:get key

127.0.0.1:6379[2]> get javastack
"666"

值遞增/遞減

如果字符串中的值是數(shù)字類型的,可以使用incr命令每次遞增,不是數(shù)字類型則報錯。

語法:incr key

127.0.0.1:6379[2]> incr javastack
(integer) 667

一次想遞增N用incrby命令,如果是浮點型數(shù)據(jù)可以用incrbyfloat命令遞增。

同樣,遞減使用decr、decrby命令。

批量存放鍵值

語法:mset key value [key value …]

127.0.0.1:6379[2]> mset java1 1 java2 2 java3 3
OK

獲取獲取鍵值

語法:mget key [key …]

127.0.0.1:6379[2]> mget java1 java2
1) "1"
2) "2"

Redis接收的是UTF-8的編碼,如果是中文一個漢字將占3位返回。

獲取值長度

語法:strlen key
127.0.0.1:6379[2]> strlen javastack
(integer) 3

追加內(nèi)容

語法:append key value

127.0.0.1:6379[2]> append javastack hi
(integer) 5

向鍵值尾部添加,如上命令執(zhí)行后由666變成666hi

獲取部分字符

語法:getrange key start end

> 127.0.0.1:6379[2]> getrange javastack 0 4
"javas"

集合操作命令

集合類型和列表類型相似,只不過是集合是無序且不可重復(fù)的。

集合

存儲值

語法:sadd key member [member …]

// 這里有8個值(2個java),只存了7個
127.0.0.1:6379> sadd langs java php c++ go ruby python kotlin java
(integer) 7

獲取元素

獲取所有元素語法:smembers key

127.0.0.1:6379> smembers langs
1) "php"
2) "kotlin"
3) "c++"
4) "go"
5) "ruby"
6) "python"
7) "java"

隨機獲取語法:srandmember langs count

127.0.0.1:6379> srandmember langs 3
1) "c++"
2) "java"
3) "php"

判斷集合是否存在元素

語法:sismember key member

127.0.0.1:6379> sismember langs go
(integer) 1

獲取集合元素個數(shù)

語法:scard key

127.0.0.1:6379> scard langs
(integer) 7

刪除集合元素

語法:srem key member [member …]

127.0.0.1:6379> srem langs ruby kotlin
(integer) 2

彈出元素

語法:spop key [count]

127.0.0.1:6379> spop langs 2
1) "go"
2) "java"

有序集合

和列表的區(qū)別:

1、列表使用鏈表實現(xiàn),兩頭快,中間慢。有序集合是散列表和跳躍表實現(xiàn)的,即使讀取中間的元素也比較快。

2、列表不能調(diào)整元素位置,有序集合能。

3、有序集合比列表更占內(nèi)存。

存儲值

語法:zadd key [NX|XX] [CH] [INCR] score member [score member …]

127.0.0.1:6379> zadd footCounts 16011 tid 20082 huny 2893 nosy
(integer) 3

獲取元素分?jǐn)?shù)

語法:zscore key member

127.0.0.1:6379> zscore footCounts tid
"16011"

獲取排名范圍排名語法:zrange key start stop [WITHSCORES]

// 獲取所有,沒有分?jǐn)?shù)
127.0.0.1:6379> zrange footCounts 0 -1
1) "nosy"
2) "tid"
3) "huny"

// 獲取所有及分?jǐn)?shù)
127.0.0.1:6379> zrange footCounts 0 -1 Withscores
1) "nosy"
2) "2893"
3) "tid"
4) "16011"
5) "huny"
6) "20082"

獲取指定分?jǐn)?shù)范圍排名語法:zrangebyscore key min max [WITHSCORES] [LIMIT offset count]

127.0.0.1:6379> zrangebyscore footCounts 3000 30000 withscores limit 0 1
1) "tid"
2) "16011"

增加指定元素分?jǐn)?shù)

語法:zincrby key increment member

127.0.0.1:6379> zincrby footCounts 2000 tid
"18011"

獲取集合元素個數(shù)

語法:zcard key

127.0.0.1:6379> zcard footCounts
(integer) 3

獲取指定范圍分?jǐn)?shù)個數(shù)

語法:zcount key min max

127.0.0.1:6379> zcount footCounts 2000 20000
(integer) 2

刪除指定元素

語法:zrem key member [member …]

127.0.0.1:6379> zrem footCounts huny
(integer) 1

獲取元素排名

語法:zrank key member

127.0.0.1:6379> zrank footCounts tid
(integer) 1

列表操作命令

列表類型是一個有序的字段串列表,內(nèi)部是使用雙向鏈表實現(xiàn),所有可以向兩端操作元素,獲取兩端的數(shù)據(jù)速度快,通過索引到具體的行數(shù)比較慢。

列表類型的元素是有序且可以重復(fù)的。

存儲值

左端存值語法:lpush key value [value …]

127.0.0.1:6379> lpush list lily sandy
(integer) 2

右端存值語法:rpush key value [value …]

127.0.0.1:6379> rpush list tom kitty
(integer) 4

索引存值語法:lset key index value

127.0.0.1:6379> lset list 3 uto
OK

彈出元素

左端彈出語法:lpop key

127.0.0.1:6379> lpop list
"sandy"

右端彈出語法:rpop key

127.0.0.1:6379> rpop list
"kitty"

獲取元素個數(shù)

語法:llen key

127.0.0.1:6379> llen list
(integer) 2

獲取列表元素

兩邊獲取語法:lrange key start stop

127.0.0.1:6379> lpush users tom kitty land pony jack maddy
(integer) 6

127.0.0.1:6379> lrange users 0 3
1) "maddy"
2) "jack"
3) "pony"
4) "land"

// 獲取所有
127.0.0.1:6379> lrange users 0 -1
1) "maddy"
2) "jack"
3) "pony"
4) "land"
5) "kitty"
6) "tom"

// 從右端索引
127.0.0.1:6379> lrange users -3 -1
1) "land"
2) "kitty"
3) "tom"

索引獲取語法:lindex key index

127.0.0.1:6379> lindex list 2
"ketty"

// 從右端獲取
127.0.0.1:6379> lindex list -5
"sady"

刪除元素

根據(jù)值刪除語法:lrem key count value

127.0.0.1:6379> lpush userids 111 222 111 222 222 333 222 222
(integer) 8

// count=0 刪除所有
127.0.0.1:6379> lrem userids 0 111
(integer) 2

// count > 0 從左端刪除前count個
127.0.0.1:6379> lrem userids 3 222
(integer) 3

// count < 0 從右端刪除前count個
127.0.0.1:6379> lrem userids -3 222
(integer) 2

范圍刪除語法:ltrim key start stop

// 只保留2-4之間的元素
127.0.0.1:6379> ltrim list 2 4
OK

散列操作命令

redis字符串類型鍵和值是字典結(jié)構(gòu)形式,這里的散列類型其值也可以是字典結(jié)構(gòu)。

存放鍵值

單個語法:hset key field value

127.0.0.1:6379> hset user name javastack
(integer) 1

多個語法:hmset key field value [field value …]

127.0.0.1:6379> hmset user name javastack age 20 address china
OK

不存在時語法:hsetnx key field value

127.0.0.1:6379> hsetnx user tall 180
(integer) 0

獲取字段值

單個語法:hget key field

127.0.0.1:6379> hget user age
"20"

多個語法:hmget key field [field …]

127.0.0.1:6379> hmget user name age address
1) "javastack"
2) "20"
3) "china"

獲取所有鍵與值語法:hgetall key

127.0.0.1:6379> hgetall user
1) "name"
2) "javastack"
3) "age"
4) "20"
5) "address"
6) "china"

獲取所有字段語法:hkeys key

127.0.0.1:6379> hkeys user
1) "name"
2) "address"
3) "tall"
4) "age"

獲取所有值語法:hvals key

127.0.0.1:6379> hvals user
1) "javastack"
2) "china"
3) "170"
4) "20"

判斷字段是否存在

語法:hexists key field

127.0.0.1:6379> hexists user address
(integer) 1

獲取字段數(shù)量

語法:hlen key

127.0.0.1:6379> hlen user
(integer) 4

遞增/減

語法:hincrby key field increment

127.0.0.1:6379> hincrby user tall -10
(integer) 170

刪除字段

語法:hdel key field [field …]

127.0.0.1:6379> hdel user age
(integer) 1

Redis 安裝

Redis 支持在 Linux、OS X 、BSD 等 POSIX 系統(tǒng)中安裝,也支持在 Windows 中安裝,在 Windows 、Linux 下的安裝

事務(wù)

redis 事務(wù)一次可以執(zhí)行多條命令,服務(wù)器在執(zhí)行命令期間,不會去執(zhí)行其他客戶端的命令請求。

事務(wù)中的多條命令被一次性發(fā)送給服務(wù)器,而不是一條一條地發(fā)送,這種方式被稱為流水線,它可以減少客戶端與服務(wù)器之間的網(wǎng)絡(luò)通信次數(shù)從而提升性能。

Redis 最簡單的事務(wù)實現(xiàn)方式是使用 MULTI 和 EXEC 命令將事務(wù)操作包圍起來。

  • 批量操作在發(fā)送 EXEC 命令前被放入隊列緩存。
  • 收到 EXEC 命令后進入事務(wù)執(zhí)行,事務(wù)中任意命令執(zhí)行失敗,其余命令依然被執(zhí)行。也就是說 Redis 事務(wù)不保證原子性。
  • 在事務(wù)執(zhí)行過程中,其他客戶端提交的命令請求不會插入到事務(wù)執(zhí)行命令序列中。

一個事務(wù)從開始到執(zhí)行會經(jīng)歷以下三個階段:

  • 開始事務(wù)。
  • 命令入隊。
  • 執(zhí)行事務(wù)。

實例

以下是一個事務(wù)的例子, 它先以 MULTI 開始一個事務(wù), 然后將多個命令入隊到事務(wù)中, 最后由 EXEC 命令觸發(fā)事務(wù), 一并執(zhí)行事務(wù)中的所有命令:

redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
QUEUED
redis 127.0.0.1:6379> GET book-name
QUEUED
redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED
redis 127.0.0.1:6379> SMEMBERS tag
QUEUED
redis 127.0.0.1:6379> EXEC
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "Mastering Series"
 2) "C++"
 3) "Programming"

單個 Redis 命令的執(zhí)行是原子性的,但 Redis 沒有在事務(wù)上增加任何維持原子性的機制,所以 Redis 事務(wù)的執(zhí)行并不是原子性的。

事務(wù)可以理解為一個打包的批量執(zhí)行腳本,但批量指令并非原子化的操作,中間某條指令的失敗不會導(dǎo)致前面已做指令的回滾,也不會造成后續(xù)的指令不做。

這是官網(wǎng)上的說明 From redis docs on transactions:
It's important to note that even when a command fails, all the other commands in the queue are processed – Redis will not stop the processing of commands.

比如:

redis 127.0.0.1:7000> multi
OK
redis 127.0.0.1:7000> set a aaa
QUEUED
redis 127.0.0.1:7000> set b bbb
QUEUED
redis 127.0.0.1:7000> set c ccc
QUEUED
redis 127.0.0.1:7000> exec
1) OK
2) OK
3) OK

如果在 set b bbb 處失敗,set a 已成功不會回滾,set c 還會繼續(xù)執(zhí)行。

Redis 事務(wù)命令

下表列出了 redis 事務(wù)的相關(guān)命令:

序號命令及描述1DISCARD 取消事務(wù),放棄執(zhí)行事務(wù)塊內(nèi)的所有命令。2EXEC 執(zhí)行所有事務(wù)塊內(nèi)的命令。3MULTI 標(biāo)記一個事務(wù)塊的開始。4UNWATCH 取消 WATCH 命令對所有 key 的監(jiān)視。5WATCH key [key ...] 監(jiān)視一個 (或多個) key ,如果在事務(wù)執(zhí)行之前這個 (或這些) key 被其他命令所改動,那么事務(wù)將被打斷。

持久化

Redis 是內(nèi)存型數(shù)據(jù)庫,為了保證數(shù)據(jù)在斷電后不會丟失,需要將內(nèi)存中的數(shù)據(jù)持久化到硬盤上。

RDB 持久化

將某個時間點的所有數(shù)據(jù)都存放到硬盤上。

可以將快照復(fù)制到其他服務(wù)器從而創(chuàng)建具有相同數(shù)據(jù)的服務(wù)器副本。

如果系統(tǒng)發(fā)生故障,將會丟失最后一次創(chuàng)建快照之后的數(shù)據(jù)。

如果數(shù)據(jù)量大,保存快照的時間會很長。

AOF 持久化

將寫命令添加到 AOF 文件(append only file)末尾。

使用 AOF 持久化需要設(shè)置同步選項,從而確保寫命令 同步到磁盤文件上的時機。這是因為對文件進行寫入并不會馬上將內(nèi)容同步到磁盤上,而是先存儲到緩沖區(qū),然后由操作系統(tǒng)決定什么時候同步到磁盤。

選項同步頻率always每個寫命令都同步eyerysec每秒同步一次no讓操作系統(tǒng)來決定何時同步

  • always 選項會嚴(yán)重減低服務(wù)器的性能
  • everysec 選項比較合適,可以保證系統(tǒng)崩潰時只會丟失一秒左右的數(shù)據(jù),并且 Redis 每秒執(zhí)行一次同步對服務(wù)器幾乎沒有任何影響。
  • no 選項并不能給服務(wù)器性能帶來多大的提升,而且會增加系統(tǒng)崩潰時數(shù)據(jù)丟失的數(shù)量。

隨著服務(wù)器寫請求的增多,AOF 文件會越來越大。Redis 提供了一種將 AOF 重寫的特性,能夠去除 AOF 文件中的冗余寫命令。

復(fù)制

通過使用 slaveof host port 命令來讓一個服務(wù)器成為另一個服務(wù)器的從服務(wù)器。

一個從服務(wù)器只能有一個主服務(wù)器,并且不支持主主復(fù)制。

連接過程

  1. 主服務(wù)器創(chuàng)建快照文件,即 RDB 文件,發(fā)送給從服務(wù)器,并在發(fā)送期間使用緩沖區(qū)記錄執(zhí)行的寫命令??煺瘴募l(fā)送完畢之后,開始像從服務(wù)器發(fā)送存儲在緩沖區(qū)的寫命令。
  2. 從服務(wù)器丟棄所有舊數(shù)據(jù),載入主服務(wù)器發(fā)來的快照文件,之后從服務(wù)器開始接受主服務(wù)器發(fā)來的寫命令。
  3. 主服務(wù)器每執(zhí)行一次寫命令,就向從服務(wù)器發(fā)送相同的寫命令。

主從鏈

隨著負載不斷上升,主服務(wù)器無法很快的更新所有從服務(wù)器,或者重新連接和重新同步從服務(wù)器將導(dǎo)致系統(tǒng)超載。為了解決這個問題,可以創(chuàng)建一個中間層來分擔(dān)主服務(wù)器的復(fù)制工作。中間層的服務(wù)器是最上層服務(wù)器的從服務(wù)器,又是最下層服務(wù)器的主服務(wù)器。

哨兵

Sentinel(哨兵)可以監(jiān)聽集群中的服務(wù)器,并在主服務(wù)器進入下線狀態(tài)時,自動從從服務(wù)器中選舉處新的主服務(wù)器。

分片

分片是將數(shù)據(jù)劃分為多個部分的方法,可以將數(shù)據(jù)存儲到多臺機器里面,這種方法在解決某些問題時可以獲得線性級別的性能提升。

假設(shè)有 4 個 Redis 實例 R0, R1, R2, R3, 還有很多表示用戶的鍵 user:1, user:2, ... , 有不同的方式來選擇一個指定的鍵存儲在哪個實例中。

  • 最簡單的是范圍分片,例如用戶 id 從 0 ~ 1000 的存儲到實例 R0 中,用戶 id 從 1001 ~ 2000 的存儲到實例 R1中,等等。但是這樣需要維護一張映射范圍表,維護操作代價高。
  • 還有一種是哈希分片。使用 CRC32 哈希函數(shù)將鍵轉(zhuǎn)換為一個數(shù)字,再對實例數(shù)量求模就能知道存儲的實例。

根據(jù)執(zhí)行分片的位置,可以分為三種分片方式:

  • 客戶端分片:客戶端使用一致性哈希等算法決定應(yīng)當(dāng)分布到哪個節(jié)點。
  • 代理分片:將客戶端的請求發(fā)送到代理上,由代理轉(zhuǎn)發(fā)到正確的節(jié)點上。
  • 服務(wù)器分片:Redis Cluster。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容