Mongodb官方驅動的進一步包裝

2021-09-08 02:01:02 字數 2759 閱讀 3760

最近有乙個需求,對資料的實時性要求比較高,之前尋找過一些記憶體資料庫,首先將收費的產品先排除掉,然後再排除一些嵌入式產品,最終留下兩個產品:

1:mysql記憶體引擎;

2:基於記憶體檔案對映的文件資料庫mongodb;

針對以上兩種產品,mysql記憶體引擎有如下缺點是我們放棄的理由:

1:資料量比較大的情況,比之innodb引擎優勢並不明顯,資料小的時候採用b-tree索引結構效能還是可以接受的。

2:記憶體引擎對於持久化是非常吃力的,如果大量資料操作均在記憶體引擎中完成,那麼就需要我們來做資料的持久化,無論是複製訂閱方式還是程式方式均存在比較大的困難。

3:記憶體引擎所占用的資料空間比較大,特別是預設的hash結構,同資料量的資料是sql server的6倍,b-tree結構未做具體比較。

選擇mongodb的理由:

1:自身具備資料的持久化;

2:對於資料的插入效能優越,特別是採用不返回值的模式,理論上來講是一種非同步操作;

3:由於文件儲存是k-value方式,所以對於單條記錄的查詢操作效能不用考慮;

4:對於水平擴充套件,資料的主從備份均非常容易。

使用mongodb過程中遇到過的問題:

1:由於儲存的內容完全由客戶端決定,於是對於一些對字段做更新的操作,比如sql 中的set count=count+1;存在乙個併發更新問題,當兩個執行緒同時需要對count欄位加1時,兩個執行緒同時查詢到的count內容為1,當執行緒a完成加1後,資料庫中實際已經變成2,此時執行緒b對count進行加1,此時也是2,於時原來是3的內容,最終會變成2。主要原因就在於更新欄位時並不會在服務端進行,欄位的內容完全是由客戶端決定,即更新時並不會像sql server一樣,在服務端變數基礎上再做操作。

解決方案:對記錄增加自定義的鎖標識,嘗試在記錄上增加鎖,如果加鎖成功,然後再查詢,如果鎖標識證明是當前執行緒才進行更新,否則迴圈嘗試加鎖。這裡有發生死鎖的可能,為此在加鎖標記時,可以增加乙個鎖時間,當超過鎖時間後,自動解鎖,這樣可以避免死鎖。

2:資料的插入,主要有兩種模式,一種是不返回處理結果,一種是返回處理結果,如果我們不太關心返回結果,那麼可以獲得最高插入效能,對於一些關注處理結果的業務場景,就需要採取返回結果方式。

3:最好自定義主鍵,不採用預設的_id值,我們處理一條學生記錄,學生記錄是唯一的,比如學生id,如果我們採用預設_id值,那麼在插入資料時也會存在併發問題:兩個執行緒同時處理學生a,當時查詢時發現資料庫中沒有學生a的記錄,於時就進行插入,由於預設的_id值是自動生成,類似guid或者是自增id,說的通俗點就是會生成乙個不重複的key,此時就會插入學生a記錄兩次,如果我們選用學生id做為主鍵,就可以避免此種情況,當第二次嘗試插入時,系統會丟擲主鍵重複的異常。

為什麼需要對mongodb驅動重新封裝?

其實無論是samus驅動還是官方驅動,其實功能都各有鞦韆,samus驅動對資料操作進行了linq封裝,即我們在操作list時,完全可以採用類似linq一樣的語法,這樣可以使我們的學習成本降低,官方驅動的特點是針對資料處理有返回值。我們的需求是即需要操作返回值也需要linq封裝,於時我找到了老趙寫的easymongo,但在它的基本上做了一小部分取捨,取捨內容如下:

1:去掉了如下邏輯,原意是將大多數操作均放在同一連線中處理,但不滿足我們的需求;我們直接對外提供一次性執行方法 

insertonsubmit,updateonsubmit,deleteonsubmit

public

void

submitchanges()}

2:對上面所提到的insert,update ,delete要求有返回值,對於insert提供兩種模式,一類是需要返回值一類則不需要。特別是像更新和刪除,我們是非常有必要知道它的處理結果,如果不關心結果,我認為可以是一些資料準確性要求不高的場景。

public

einsertstatus insertonsubmit(tentity entity)

public

einsertstatus insertonsubmit(tentity entity, esafemode safemode)

public

void

insertbatchonsubmit(list

<

tentity

>

entity)

public

bool

updateonsubmit(tentity entity)

public

bool

deleteonsubmit(tentity entity)

3:對查詢的修改,在將實體對映為mongo文件時,需要對我們自定義的實體提供乙個map,這個map主要是為了標識哪個是主鍵,哪些欄位是可以被linq識別的字段,比如我們要按學生id查詢,就需要在map中增加此欄位,示例如下:

public

class

aggregatecompanyrecruitstudentinfomap : entitymap

<

aggregatecompanyrecruitstudentinfo

>}

但原始碼中的查詢,如果沒有提供查詢表示式,則預設只返回map中提到的字段,對其它實體欄位則不處理,為此修改如下:即沒有查詢表示式的情況返回完整文件。

fieldsdocument fieldsdoc 

=null;if

(null

!=selector)

{fieldsdoc =

4:去掉原有複雜的更新邏輯,刪除對我們沒用的狀態跟蹤,要的就是簡單直接,過於複雜的邏輯不利於開發。

mymongo的乙個簡化結構圖分享給大家:

bufferedReader進一步理解

public static void main string args string mystring system.out.println 請輸入明文 bufferedreader buf new bufferedreader new inputstreamreader system.in try...

Looper Handler進一步學習

package com.test.looper import android.os.bundle import android.os.handler import android.os.handlerthread import android.os.looper import android.os....

進一步了解Makefile

mkdir p add src 一層一層建立目錄。touch add makefile 建立 makefile include 目錄中存放標頭檔案。scripts 存放指令碼檔案。存放方式 按照核心管理原始碼來管理。為什麼學習makefile?編譯大型專案 讀懂別人的開源 找到程式入口 看專案的順序...