文章目錄
- 模板還是繼承?
- 新的方案——泛化資料操作,特化基礎資料庫操作
- 泛化資料操作
nosql資料庫redis提供了一系列的C介面,使用比較方便,但是對於一些任務,仍然存在很大的代碼重複性,為瞭解決這種代碼重複的問題,本文擬封裝這些操作。
關於redis的命令,可以參考http://redis.readthedocs.org。
模板還是繼承?這是一個困擾我很多天的問題:如果想要實現一個通用的類庫,需要相容多種的寫入資料類型,如何統一?如果使用了類模板,那麼,統一介面的問題得以解決,但是,可能引入了需要為不同的資料類型特化介面的問題——結果就是引入了一個需要為每一種資料結構實現不同 操作工作的monster。這種設計,不得不說是一個維護和擴充的噩夢。新的方案——泛化資料操作,特化基礎資料庫操作經過幾天的考慮,最終想到了另外的解決方案:基類中使用proteced實現所有的資料庫基本操作類型,例如:
- Key(鍵)
- DEL
- KEYS
- RANDOMKEY
- TTL
- PTTL
- EXISTS
- MOVE
- RENAME
- RENAMENX
- TYPE
- EXPIRE
- PEXPIRE
- EXPIREAT
- PEXPIREAT
- PERSIST
- SORT
- OBJECT
- MIGRATE
|
像這些操作,可以很好的整合在基類中,不會存在資料的不同帶來的不同操作。
對於和資料相關的操作,可能由於資料的不同,造成不同的操作方式,因此採用一些泛化的技術進行實現。泛化資料操作下面將根據redis支援的不同資料結構做泛化的分析。stringstring是redis中最簡單、基礎的一種資料結構,但是也是用法最為複雜的一種結構,其原因就是string的資料類型能夠保證其是二進位安全的,value可以儲存任何東西,從一幅圖片到一部電影,只要在記憶體限制的範圍內(512MB),you are the boss:
- string可以簡單的被用為key-value儲存介質(set,mset,get,mget...)
- 可以使用value儲存int,float做相關的統計工作(incr,decr,incrby,decrby,incrbyfloat)
- string可以被用作bitset去做bitset的工作。(對應的命令為getbit和setbit)
在redis的官網上是這麼說的:
- Use Strings as atomic counters using commands in the INCR family: INCR, DECR, INCRBY.(用作原子計數器)
- Append to strings with the APPEND command.(添加資料到string的尾部)
- Use Strings as a random access vectors with GETRANGE and SETRANGE.(把string當做隨機訪問向量)
- Encode a lot of data in little space, or create a Redis backed Bloom Filter using GETBIT and SETBIT.(編碼壓縮,布隆過濾器)
string中支援的操作如下:String(字串)
- SET
- SETNX
- SETEX
- PSETEX
- SETRANGE
- MSET
- MSETNX
- APPEND
- GET
- MGET
- GETRANGE
- GETSET
- STRLEN
- DECR
- DECRBY
- INCR
- INCRBY
- INCRBYFLOAT
- SETBIT
- GETBIT
根據上述的分析,對於數實值型別的操作可以不考慮介面參數的泛化問題,整數的操作可以直接設定為int,浮點數的操作設定為double;但是對於set和mset等操作,為了支援多種資料結構,我們可以首先對資料結構本身做一個抽象,使之提供抽象的toString介面、string2member的介面,以及參數為string類型的建構函式。這樣,只要是該種資料結構,就可以使用多態的方式很好的完成set以及mset的操作(為什麼要提供這樣的操作?主要的核心思想是考慮到了value儲存欄位的特化,可以用一個value的字串來儲存多種資訊,為啥不用hash呢?最大的優點在於比hash的操作簡單——hash需要多次取值)。hashhash同樣也是每一個nosql必須支援的資料結構,對於redis來說,其儲存結構為key-filed-value形式,即key後跟filed,filed再跟value的值。同上述的討論,當需要寫入的資料結構較為複雜的時候,同樣需要採用處理string中value的方式來處理hash中的value資料。redis支援的操作如下:Hash(雜湊表)
- HSET
- HSETNX
- HMSET
- HGET
- HMGET
- HGETALL
- HDEL
- HLEN
- HEXISTS
- HINCRBY
- HINCRBYFLOAT
- HKEYS
- HVALS
同樣,在介面中,key和filed可以固定為char*的類型,為了支援value的可擴充性,value接受的值的類型可以是上文中提到的抽象的資料結構(支援轉化為string和由string產生)。
listredis的list是個人認為最為飄逸的一個資料結構實現,可以使用list實現生產者、消費者模型(BLPOP,BRPOP),可以使用list實現迴圈隊列(RPOPLPUSH, BRPOPLPUSH)。合上述的討論一致,對該資料結構儲存的value也採用上述的抽象資料格式實現。List(列表)
- LPUSH
- LPUSHX
- RPUSH
- RPUSHX
- LPOP
- RPOP
- BLPOP
- BRPOP
- LLEN
- LRANGE
- LREM
- LSET
- LTRIM
- LINDEX
- LINSERT
- RPOPLPUSH
- BRPOPLPUSH
setredis的集合底層根據筆者推算是根據list做到的實現,set支援交集,並集以及差集的運算,這些運算在做統計工作的時候是非常有效。由於不care資料,只關心key,對於set的操作,可以使用內建的資料類型。Set(集合)
- SADD
- SREM
- SMEMBERS
- SISMEMBER
- SCARD
- SMOVE
- SPOP
- SRANDMEMBER
- SINTER
- SINTERSTORE
- SUNION
- SUNIONSTORE
- SDIFF
- SDIFFSTORE
有續集sorted set有續集合的儲存格式是key [score member] [...]值和成員的對,sorted set添加、刪除和更新元素的時間複雜度為logN這裡仍然採用上文提及的抽象資料成員的解決方案。有序集(Sorted set)
- ZADD
- ZREM
- ZCARD
- ZCOUNT
- ZSCORE
- ZINCRBY
- ZRANGE
- ZREVRANGE
- ZRANGEBYSCORE
- ZREVRANGEBYSCORE
- ZRANK
- ZREVRANK
- ZREMRANGEBYRANK
- ZREMRANGEBYSCORE
- ZINTERSTORE
- ZUNIONSTORE