Mongodb官方驅動的進一步封裝

來源:互聯網
上載者:User

 

    最近有一個需求,對資料的即時性要求比較高,之前尋找過一些記憶體資料庫,首先將收費的產品先排除掉,然後再排除一些嵌入式產品,最終留下兩個產品:
    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()
        {
            using (this.Database.Server.RequestStart(this.Database))
            {
                this.DeleteEntities();
                this.UpdateEntites();
                this.InsertEntities();
            }
        }

 

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

   

     public EInsertstatus InsertOnSubmit(TEntity entity)
        {
            if (entity == null) throw new ArgumentNullException();
            return this.InsertEntities(entity,ESafeMode.False);
        }
        public EInsertstatus InsertOnSubmit(TEntity entity, ESafeMode safeMode)
        {
            if (entity == null) throw new ArgumentNullException();
            return this.InsertEntities(entity, safeMode);
        }
        public void InsertBatchOnSubmit(List<TEntity> entity)
        {
            if (entity == null) throw new ArgumentNullException();
            this.InsertBatchEntities(entity);
        }
        public bool UpdateOnSubmit(TEntity entity)
        {
            if (entity == null) throw new ArgumentNullException();
            return this.UpdateEntites(entity);
        }
        public bool DeleteOnSubmit(TEntity entity)
        {
            if (entity == null) throw new ArgumentNullException();

            return this.DeleteEntities(entity);
        }

        
     3:對查詢的修改,在將實體映射為mongo文檔時,需要對我們自訂的實體提供一個Map,這個Map主要是為了標識哪個是主鍵,哪些欄位是可以被Linq識別的欄位,比如我們要按學生ID查詢,就需要在Map中增加此欄位,樣本如下:
        

public class AggregateCompanyRecruitStudentInfoMap : EntityMap<AggregateCompanyRecruitStudentInfo>
    {
        public AggregateCompanyRecruitStudentInfoMap()
        {
            Collection("AggregateCompanyRecruitStudentInfo");
            Property(n => n.OrganizationID).Identity();
            Property(n => n.LockTime);
            Property(n => n.LockFiled);

        }
    }

 

    但源碼中的查詢,如果沒有提供查詢運算式,則預設只返回Map中提到的欄位,對其它實體欄位則不處理,為此修改如下:即沒有查詢運算式的情況返回完整文檔。
       

 FieldsDocument fieldsDoc = null;
            if (null != selector)
            {
                fieldsDoc = mapper.GetFields(selector);
            }

 

    4:去掉原有複雜的更新邏輯,刪除對我們沒用的狀態跟蹤,要的就是簡單直接,過於複雜的邏輯不利於開發。
       
    Mymongo的一個簡化結構圖分享給大家:


       
       說明:最後歡迎大家交流mongodb,文中如有不對的地方,希望批評指正,大家共同進步。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.