Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 日韩一级片免费,国产99久9在线,久久综合九色综合精品

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          在 Linux 上配置 mongodb

          ongoDB 是一個(gè)介于關(guān)系數(shù)據(jù)庫(kù)和非關(guān)系數(shù)據(jù)庫(kù)之間的產(chǎn)品,是非關(guān)系數(shù)據(jù)庫(kù)當(dāng)中功能最豐富,最像關(guān)系數(shù)據(jù)庫(kù)的。他支持的數(shù)據(jù)結(jié)構(gòu)非常松散,是類似json的bson格式,因此可以存儲(chǔ)比較復(fù)雜的數(shù)據(jù)類型。Mongo最大的特點(diǎn)是他支持的查詢語(yǔ)言非常強(qiáng)大,其語(yǔ)法有點(diǎn)類似于面向?qū)ο蟮牟樵冋Z(yǔ)言,幾乎可以實(shí)現(xiàn)類似關(guān)系數(shù)據(jù)庫(kù)單表查詢的絕大部分功能,而且還支持對(duì)數(shù)據(jù)建立索引。

          1.下載Linux安裝包

          如下圖,放到本地的某個(gè)角落,要記得位置哦~

          2.連接你的服務(wù)器

          ssh root@你的IP //回車輸入密碼 

          3.安裝包上傳

          另開ssh窗口(command+n),如果是windows就打開新的cmd窗口,因?yàn)槲覀円僮鞅镜匚募暗拇翱谖覀円呀?jīng)登了服務(wù)器了。傳的方法很多,我只演示其中一種。
          cd "安裝包所在文件夾" // 去你剛才安裝包放的位置
          scp "本地文件" root@你的IP // 回車輸入密碼開始傳送

          如下圖,我是傳送到服務(wù)器的根目錄下。其實(shí)不建議,你可以放在一個(gè)固有目錄,比如/usr/local


          ls -l //以列表的形式展開,我們可以看到已經(jīng)下載成功了。

          4.解壓安裝包

          tar -zxvf mongodb-linux-x86_64-3.4.6.tgz //解壓 不同文件有不同的解壓命令,自己百度即可

          5.填坑的一步

          剛才說(shuō)大家可以把每次安裝的東東放到固定的文件夾,所以我把解壓好的文件移到了 /usr/local/mongodb目錄了,如果你已經(jīng)放到了你喜歡的位置,可以跳過(guò)此步驟。如果你不知道怎么移,可以看下。
          cd /user/local //進(jìn)入local
          mkdir mongodb //創(chuàng)建mongodb文件夾
          cd / //進(jìn)入根目錄
          mv mongodb-linux-x86_64-3.4.6 /usr/local/mongodb /*將剛才的解壓包移入 /usr/local/mongodb*/

          6.配置mongodb運(yùn)行環(huán)境

          mkdir data //創(chuàng)建data文件夾,存放數(shù)據(jù)庫(kù)db文件  
          mkdir logs //創(chuàng)建logs文件夾,存放日志文件  
          cd logs //進(jìn)入logs  
          touch mongo.log //創(chuàng)建log文件  
          cd .. //返回上一級(jí)  
          mkdir etc //創(chuàng)建配置文件夾  
          cd etc // 進(jìn)入etc  
          vim mongo.conf //編輯同時(shí)創(chuàng)建mongo.conf 文件

          以下是mongo.conf文件里的代碼,大家看好不要寫錯(cuò),進(jìn)入文件之后要按一下鍵盤i才能開始編寫代碼。

          dbpath = /usr/local/mongodb/data //路徑一定要輸入絕對(duì)的  
          logpath = /usr/local/mongodb/logs/mongo.log //路徑一定要輸入絕對(duì)的  
          logappend = true  
          journal = true  
          quiet = true  
          port = 27017 //端口

          寫好了按esc鍵退出,然后按shift+:會(huì)在最下面出現(xiàn):然后輸入wq,保存并退出的意思。


          到了這一步就接近尾聲了。

          7.啟動(dòng)mongodb

          cd mongodb/mongodb-linux-x86_64-3.4.6/bin //進(jìn)入安裝包的bin目錄下 
          mongod -f /usr/local/mongodb/etc/mongo.conf  //啟動(dòng)1方法  或 ./mongod -f /usr/local/mongodb/etc/mongo.conf  //啟動(dòng)2方法  

          如果輸入這個(gè)命令,出現(xiàn)如下圖,沒什么變化,只有光標(biāo)閃爍。

          8.本地測(cè)試是否成功

          我用的可視化工具 Robo 3t,新建鏈接,address輸入服務(wù)器地址,端口填你mongo.conf里配置的,基本都是27027。


          點(diǎn)擊保存,如下圖操作,進(jìn)行 Connect。


          如果到了這一步基本就是成功啦。

          9.小坑警示

          我之前在mongo.conf 里 路徑寫的是相對(duì)的,就出現(xiàn)了下面的問(wèn)題。

          然后就是這樣子的。

          10.總結(jié)

          方法有很多,我寫的只是其中一種,自己也是第一次安裝。其中也有點(diǎn)坑坑,遇到問(wèn)題不要認(rèn)輸,總會(huì)解決的,寫的不對(duì)不好的地方,希望大家不吝賜教~

          本文地址:https://www.linuxprobe.com/linux-mongodb.html

          光鬧鐘app開發(fā)者,請(qǐng)關(guān)注我,后續(xù)分享更精彩!

          堅(jiān)持原創(chuàng),共同進(jìn)步!

          概述

          MongoDB是一個(gè)可擴(kuò)展,高性能,開源,面向文檔的,基于鍵/值類型的數(shù)據(jù)庫(kù)。非常適合保存大對(duì)象及json格式的數(shù)據(jù)。本文將介紹MongoDB的單機(jī)和集群副本安裝,記錄下來(lái)以備后用。希望對(duì)有需要的朋友有所幫助和參考。

          下載地址

          # 歷史產(chǎn)品和版本選擇
          https://www.mongodb.com/docs/legacy/
          
          # 3.6版本文檔地址
          https://www.mongodb.com/docs/v3.6/

          安裝方式

          • StandAlone:?jiǎn)螜C(jī)環(huán)境,一般開發(fā)測(cè)試的時(shí)候用。
          • Replication:主從結(jié)構(gòu),一個(gè)Primary,多個(gè)Secondary,可能會(huì)有Arbitry。
          - Primary掛掉之后,會(huì)選舉出一個(gè)Secondary作為Primary,與zookeeper類似。
          - Arbitry(仲裁節(jié)點(diǎn))上面不存數(shù)據(jù),只是為了湊數(shù)。選舉算法要求節(jié)點(diǎn)數(shù)必須是奇數(shù)個(gè),如果Primary+Secondary不是奇數(shù)個(gè),就要用Arbitry湊數(shù)。
          - 寫數(shù)據(jù)只能在Primary,讀數(shù)據(jù)默認(rèn)也在Primary,可以配置成從Secondary讀,可以選最近的節(jié)點(diǎn)。
          - 數(shù)據(jù)在Primary上寫成功之后,會(huì)將操作記錄在oplog中,Secondary將oplog拷貝過(guò)去,然后照著操作一遍,就有數(shù)據(jù)了。
          - Primary和Secondary上面的數(shù)據(jù)保證最終一致性,可以為寫操作配置write concern,有幾個(gè)級(jí)別:在Primary上寫完就認(rèn)為寫成功;寫到oplog后認(rèn)為寫成功;寫到一個(gè)/多個(gè)/某個(gè)/某幾個(gè)Secondary之后認(rèn)為寫成功,等等。
          • Sharding:share nothing的結(jié)構(gòu),每臺(tái)機(jī)器只存一部分?jǐn)?shù)據(jù)。mongod服務(wù)器存數(shù)據(jù),mongos服務(wù)器負(fù)責(zé)路由讀寫請(qǐng)求,元數(shù)據(jù)存在config數(shù)據(jù)庫(kù)中。

          安裝&準(zhǔn)備

          centos 系統(tǒng) yum源創(chuàng)建

          cat >/etc/yum.repos.d/mongodb-org-3.6.repo<<eof
          [mongodb-org-3.6]
          name=MongoDB Repository
          baseurl=https://repo.mongodb.org/yum/redhat/6Server/mongodb-org/3.6/x86_64/
          gpgcheck=1
          enabled=1
          gpgkey=https://www.mongodb.org/static/pgp/server-3.6.asc
          eof

          根據(jù)具體情況,選擇版本安裝

          # 安裝最近版本
          # sudo yum install -y mongodb-org
          
          # 安裝指定版本
          sudo yum install --disablerepo=kubernetes -y mongodb-org-3.6.8 mongodb-org-server-3.6.8 mongodb-org-shell-3.6.8 mongodb-org-mongos-3.6.8 mongodb-org-tools-3.6.8

          StandAlone安裝配置

          默認(rèn)配置文件/etc/mongod.conf

          - storage.dbPath 數(shù)據(jù)存儲(chǔ)目錄
          - systemLog.path 系統(tǒng)日志目錄
          - net.bindIp 訪問(wèn)ip綁定,默認(rèn)127.0.0.1。需要外部機(jī)器連接時(shí),需調(diào)整成新人的訪問(wèn)源ip,或者測(cè)試所有ip放開0.0.0.0

          啟動(dòng)MongoDB

          sudo systemctl start mongod
          # 如果啟動(dòng)報(bào)如下報(bào)錯(cuò)
          # Failed to start mongod.service: Unit mongod.service not found.
          # 啟動(dòng)以下命令
          # sudo systemctl daemon-reload

          查看MongoDB狀態(tài)

          sudo systemctl status mongod
          # 如果想要重啟系統(tǒng)MongoDB服務(wù)自動(dòng)啟動(dòng),可設(shè)置以下命令
          # sudo systemctl enable mongod

          停止MongoDB

          sudo systemctl stop mongod

          重啟MongoDB

          sudo systemctl restart mongod

          連接MongoDB

          mongo --host 127.0.0.1:27017

          Replication安裝

          參考文檔

          官方文檔:https://www.mongodb.com/docs/v3.6/administration/replica-set-deployment/

          環(huán)境

          3個(gè)節(jié)點(diǎn)分別安裝MongoDB實(shí)例

          修改/etc/mongod.conf以下配置項(xiàng):

          #replica set的名字
          replication:
             replSetName: "rs0"
             
          #client訪問(wèn)ip綁定,開發(fā)測(cè)試0.0.0.0所有ip   
          net:
             bindIp: localhost,<ip address>  

          分別在3個(gè)節(jié)點(diǎn)上啟動(dòng)MongoDB服務(wù)

          sudo systemctl start mongod
          # 如果啟動(dòng)報(bào)如下報(bào)錯(cuò)
          # Failed to start mongod.service: Unit mongod.service not found.
          # 啟動(dòng)以下命令
          # sudo systemctl daemon-reload

          Initiate the replica set(初始化副本集)

          任意一個(gè)節(jié)點(diǎn)控制臺(tái)登錄MongoDB

          [root@dev2 ~]# mongo
          MongoDB shell version v3.6.8
          connecting to: mongodb://127.0.0.1:27017
          MongoDB server version: 3.6.8
          Server has startup warnings:
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten]
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten]
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten]
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten]
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten]
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten] ** WARNING: soft rlimits too low. rlimits set to 4096 processes, 64000 files. Number of processes should be at least 32000 : 0.5 times number of files.
          2022-05-11T09:36:02.035+0800 I CONTROL  [initandlisten]
          >

          初始化副本集。 注:只需在集群一臺(tái)機(jī)器上執(zhí)行初始化命令。

          rs.initiate( {
             _id : "rs0",
             members: [
                { _id: 0, host: "dev2:27017" },
                { _id: 1, host: "dev3:27017" },
                { _id: 2, host: "dev4:27017" }
             ]
          })

          執(zhí)行結(jié)果如下:

          > rs.initiate( {
          ...    _id : "rs0",
          ...    members: [
          ...       { _id: 0, host: "dev2:27017" },
          ...       { _id: 1, host: "dev3:27017" },
          ...       { _id: 2, host: "dev4:27017" }
          ...    ]
          ... })
          {
                  "ok" : 1,
                  "operationTime" : Timestamp(1653010782, 1),
                  "$clusterTime" : {
                          "clusterTime" : Timestamp(1653010782, 1),
                          "signature" : {
                                  "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                                  "keyId" : NumberLong(0)
                          }
                  }
          }

          查看配置結(jié)果:控制臺(tái)執(zhí)行以下指令

          rs.conf()

          附錄

          家好,我是Edison。

          最近工作中需要用到MongoDB的事務(wù)操作,因此參考了一些資料封裝了一個(gè)小的組件,提供基礎(chǔ)的CRUD Repository基類 和 UnitOfWork工作單元模式。今天,就來(lái)簡(jiǎn)單介紹一下這個(gè)小組件。

          關(guān)于MongoDB的事務(wù)

          MongoDB在4.2版本開始全面支持了多文檔事務(wù),至今已過(guò)了四年了,雖然我們可能沒有在項(xiàng)目中用MongoDB來(lái)替代傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)如MySQL/SQL Server,但是不能否認(rèn)MongoDB已經(jīng)在事務(wù)能力上愈發(fā)成熟了。

          在MongoDB中,所謂的事務(wù)主要指的是多個(gè)文檔的事務(wù),其使用方式和傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)差不多。但我們需要注意的是:多文檔事務(wù)只能應(yīng)用在副本集 或 mongos 節(jié)點(diǎn)上。如果你只是一個(gè)單點(diǎn)的mongo實(shí)例,是無(wú)法進(jìn)行多文檔事務(wù)實(shí)踐的。

          畫外音:如果你對(duì)MongoDB感興趣,不妨看看我的這個(gè)系列博客:《MongoDB入門到實(shí)踐學(xué)習(xí)之旅

          那么,如何快速進(jìn)行事務(wù)操作呢?

          在Mongo Shell中進(jìn)行事務(wù)
          下面演示了如何通過(guò)Mongo Shell來(lái)進(jìn)行一個(gè)多文檔操作的事務(wù)提交:
          • var session = db.getMongo().startSession();session.startTransaction({readConcern: { level: 'majority' },writeConcern: { w: 'majority' }});
            var coll1 = session.getDatabase('students').getCollection('teams');coll1.update({name: 'yzw-football-team'}, {$set: {members: 20}});
            var coll2 = session.getDatabase('students').getCollection('records');coll1.update({name: 'Edison'}, {$set: {gender: 'Female'}});
            // 成功提交事務(wù)session.commitTransaction();
            // 失敗事務(wù)回滾session.abortTransaction();
            在.NET應(yīng)用中進(jìn)行事務(wù)
            下面展示了在.NET應(yīng)用中通過(guò)MongoDB Driver來(lái)進(jìn)行事務(wù)的示例:
            • using (var clientSession = mongoClient.StartSession()){ try { var contacts = clientSession.Client.GetDatabase("testDB").GetCollection<Contact>("contacts"); contacts.ReplaceOne(contact => contact.Id == "1234455", contact); var books = clientSession.Client.GetDatabase("testDB").GetCollection<Book>("books"); books.DeleteOne(book => book.Id == "1234455");
              clientSession.CommitTransaction(); } catch (Exception ex) { // to do some logging clientSession.AbortTransaction(); }}
              在大部分的實(shí)際應(yīng)用中,我們通常都習(xí)慣使用數(shù)據(jù)倉(cāng)儲(chǔ)(Repository)的模式來(lái)進(jìn)行CRUD,同時(shí)也習(xí)慣用工作單元(UnitOfWork)模式來(lái)進(jìn)行協(xié)調(diào)多個(gè)Repository進(jìn)行事務(wù)提交
              那么,如何在自己的項(xiàng)目中實(shí)現(xiàn)這個(gè)呢?
              參考了一些資料后,自己實(shí)現(xiàn)了一個(gè)基礎(chǔ)小組件,暫且叫它:EDT.MongoProxy吧,我們來(lái)看看它是如何實(shí)現(xiàn)的。
              單例的MongoClient
              基于MongoDB的最佳時(shí)間,對(duì)于MongoClient最好設(shè)置為單例注入,這樣可以避免反復(fù)實(shí)例化MongoClient帶來(lái)的開銷,避免在極端情況下的性能低下。
              這里暫且設(shè)計(jì)一個(gè)MongoDbConnection類,用于包裹這個(gè)MongoClient,然后將其以單例模式注入IoC容器中。
              • public class MongoDbConnection : IMongoDbConnection{ public IMongoClient DatabaseClient { get; } public string DatabaseName { get; }
                public MongoDbConnection(MongoDatabaseConfigs configs, IConfiguration configuration) { DatabaseClient = new MongoClient(configs.GetMongoClientSettings(configuration)); DatabaseName = configs.DatabaseName; }}
                其中,這個(gè)MongoDatabaseConfigs類主要是獲取appsettings中的配置,用以生成MongoClient的對(duì)應(yīng)Settings。
                • /** Config Example"MongoDatabaseConfigs": { "Servers": "xxx01.edisontalk.net,xxx02.edisontalk.net,xxx03.edisontalk.net", "Port": 27017, "ReplicaSetName": "edt-replica", "DatabaseName": "EDT_Practices", "AuthDatabaseName": "admin",
                  "ApplicationName": "Todo", "UserName": "service_testdev", "Password": "xxxxxxxxxxxxxxxxxxxxxxxx", "UseTLS": true, "AllowInsecureTLS": true, "SslCertificatePath": "/etc/pki/tls/certs/EDT_CA.cer", "UseEncryption": true}**/public class MongoDatabaseConfigs{ private const string DEFAULT_AUTH_DB = "admin"; // Default AuthDB: admin
                  public string Servers { get; set; } public int Port { get; set; } = 27017; // Default Port: 27017 public string ReplicaSetName { get; set; } public string DatabaseName { get; set; } public string DefaultCollectionName { get; set; } = string.Empty; public string ApplicationName { get; set; } public string UserName { get; set; } public string Password { get; set; } public string AuthDatabaseName { get; set; } = DEFAULT_AUTH_DB; // Default AuthDB: admin public string CustomProperties { get; set; } = string.Empty; public bool UseTLS { get; set; } = false; public bool AllowInsecureTLS { get; set; } = true; public string SslCertificatePath { get; set; } = string.Empty; public bool StoreCertificateInKeyStore { get; set; } = false;

                  public MongoClientSettings GetMongoClientSettings(IConfiguration configuration = ) { if (string.IsOrWhiteSpace(Servers)) throw new ArgumentException("Mongo Servers Configuration is Missing!");
                  if (string.IsOrWhiteSpace(UserName) || string.IsOrWhiteSpace(Password)) throw new ArgumentException("Mongo Account Configuration is Missing!");
                  // Base Configuration MongoClientSettings settings = new MongoClientSettings { ApplicationName = ApplicationName, ReplicaSetName = ReplicaSetName };

                  // Credential settings.Credential = MongoCredential.CreateCredential(AuthDatabaseName, UserName, Password);
                  // Servers var mongoServers = Servers.Split(",", StringSplitOptions.RemoveEmptyEntries).ToList(); if (mongoServers.Count == 1) // Standalone { settings.Server = new MongoServerAddress(mongoServers.First(), Port); settings.DirectConnection = true; }
                  if (mongoServers.Count > 1) // Cluster { var mongoServerAddresses = new List<MongoServerAddress>(); foreach (var mongoServer in mongoServers) { var mongoServerAddress = new MongoServerAddress(mongoServer, Port); mongoServerAddresses.Add(mongoServerAddress); } settings.Servers = mongoServerAddresses; settings.DirectConnection = false; }
                  // SSL if (UseTLS) { settings.UseTls = true; settings.AllowInsecureTls = AllowInsecureTLS; if (string.IsOrWhiteSpace(SslCertificatePath)) throw new ArgumentException("SslCertificatePath is Missing!");
                  if (StoreCertificateInKeyStore) { var localTrustStore = new X509Store(StoreName.Root); var certificateCollection = new X509Certificate2Collection(); certificateCollection.Import(SslCertificatePath); try { localTrustStore.Open(OpenFlags.ReadWrite); localTrustStore.AddRange(certificateCollection); } catch (Exception ex) { throw; } finally { localTrustStore.Close(); } }
                  var certs = new List<X509Certificate> { new X509Certificate2(SslCertificatePath) }; settings.SslSettings = new SslSettings(); settings.SslSettings.ClientCertificates = certs; settings.SslSettings.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls13; }
                  return settings; }}
                  核心部分:MongoDbContext
                  這里我們主要仿照DbContext的設(shè)計(jì),設(shè)計(jì)一個(gè)MongoDbContext,它從IoC容器中獲取到單例的MongoClient,封裝了事務(wù)的開啟和提交,簡(jiǎn)化了應(yīng)用代碼的編寫
                  • public class MongoDbContext : IMongoDbContext{ private readonly IMongoDatabase _database; private readonly IMongoClient _mongoClient; private readonly IList<Func<IClientSessionHandle, Task>> _commands = new List<Func<IClientSessionHandle, Task>>();
                    public MongoDbContext(IMongoDbConnection dbClient) { _mongoClient = dbClient.DatabaseClient; _database = _mongoClient.GetDatabase(dbClient.DatabaseName); }
                    public void AddCommand(Func<IClientSessionHandle, Task> func) { _commands.Add(func); }
                    public async Task AddCommandAsync(Func<IClientSessionHandle, Task> func) { _commands.Add(func); await Task.CompletedTask; }
                    /// <summary> /// NOTES: Only works in Cluster mode /// </summary> public int Commit(IClientSessionHandle session) { try { session.StartTransaction();
                    foreach (var command in _commands) { command(session); }
                    session.CommitTransaction(); return _commands.Count; } catch (Exception ex) { session.AbortTransaction(); return 0; } finally { _commands.Clear(); } }
                    /// <summary> /// NOTES: Only works in Cluster mode /// </summary> public async Task<int> CommitAsync(IClientSessionHandle session) { try { session.StartTransaction();
                    foreach (var command in _commands) { await command(session); }
                    await session.CommitTransactionAsync(); return _commands.Count; } catch (Exception ex) { await session.AbortTransactionAsync(); return 0; } finally { _commands.Clear(); } }
                    public IClientSessionHandle StartSession() { var session = _mongoClient.StartSession(); return session; }
                    public async Task<IClientSessionHandle> StartSessionAsync() { var session = await _mongoClient.StartSessionAsync(); return session; }
                    public IMongoCollection<T> GetCollection<T>(string name) { return _database.GetCollection<T>(name); }
                    public void Dispose() { GC.SuppressFinalize(this); }}

                    數(shù)據(jù)倉(cāng)儲(chǔ):MongoRepositoryBase

                    在實(shí)際項(xiàng)目中,我們都希望有一個(gè)基礎(chǔ)的RepositoryBase類,將CRUD的方法都封裝了,我們實(shí)際中就只需要?jiǎng)?chuàng)建一個(gè)對(duì)應(yīng)的Repository集成這個(gè)RepositoryBase就行了,無(wú)需再重復(fù)編寫CRUD的方法。那么,也就有了這個(gè)MongoRepositoryBase類:

                    • public class MongoRepositoryBase<TEntity> : IMongoRepositoryBase<TEntity> where TEntity : MongoEntityBase, new(){ protected readonly IMongoDbContext _dbContext; protected readonly IMongoCollection<TEntity> _dbSet; private readonly string _collectionName; private const string _keyField = "_id";
                      public MongoRepositoryBase(IMongoDbContext mongoDbContext) { _dbContext = mongoDbContext; _collectionName = typeof(TEntity).GetAttributeValue((TableAttribute m) => m.Name) ?? typeof(TEntity).Name; if (string.IsOrWhiteSpace(_collectionName)) throw new ArgumentException("Mongo DatabaseName can't be ! Please set the attribute Table in your entity class.");
                      _dbSet = mongoDbContext.GetCollection<TEntity>(_collectionName); }
                      #region Create Part
                      public async Task AddAsync(TEntity entity, IClientSessionHandle session = ) { if (session == ) await _dbSet.InsertOneAsync(entity); else await _dbContext.AddCommandAsync(async (session) => await _dbSet.InsertOneAsync(entity)); }
                      public async Task AddManyAsync(IEnumerable<TEntity> entityList, IClientSessionHandle session = ) { if (session == ) await _dbSet.InsertManyAsync(entityList); else await _dbContext.AddCommandAsync(async (session) => await _dbSet.InsertManyAsync(entityList)); }
                      #endregion
                      # region Delete Part
                      public async Task DeleteAsync(string id, IClientSessionHandle session = ) { if (session == ) await _dbSet.DeleteOneAsync(Builders<TEntity>.Filter.Eq(_keyField, new ObjectId(id))); else await _dbContext.AddCommandAsync(async (session) => await _dbSet.DeleteOneAsync(Builders<TEntity>.Filter.Eq(_keyField, new ObjectId(id)))); }
                      public async Task DeleteAsync(Expression<Func<TEntity, bool>> expression, IClientSessionHandle session = ) { if (session == ) await _dbSet.DeleteOneAsync(expression); else await _dbContext.AddCommandAsync(async (session) => await _dbSet.DeleteOneAsync(expression)); }
                      public async Task<DeleteResult> DeleteManyAsync(FilterDefinition<TEntity> filter, IClientSessionHandle session = ) { if (session == ) return await _dbSet.DeleteManyAsync(filter);
                      await _dbContext.AddCommandAsync(async (session) => await _dbSet.DeleteManyAsync(filter)); return new DeleteResult.Acknowledged(10); }
                      public async Task<DeleteResult> DeleteManyAsync(Expression<Func<TEntity, bool>> expression, IClientSessionHandle session = ) { if (session == ) return await _dbSet.DeleteManyAsync(expression);
                      await _dbContext.AddCommandAsync(async (session) => await _dbSet.DeleteManyAsync(expression)); return new DeleteResult.Acknowledged(10); }
                      #endregion
                      #region Update Part
                      public async Task UpdateAsync(TEntity entity, IClientSessionHandle session = ) { if (session == ) await _dbSet.ReplaceOneAsync(item => item.Id == entity.Id, entity); else await _dbContext.AddCommandAsync(async (session) => await _dbSet.ReplaceOneAsync(item => item.Id == entity.Id, entity)); }
                      public async Task UpdateAsync(Expression<Func<TEntity, bool>> expression, Expression<Action<TEntity>> entity, IClientSessionHandle session = ) { var fieldList = new List<UpdateDefinition<TEntity>>();
                      if (entity.Body is MemberInitExpression param) { foreach (var item in param.Bindings) { var propertyName = item.Member.Name; object propertyValue = ;
                      if (item is not MemberAssignment memberAssignment) continue;
                      if (memberAssignment.Expression.NodeType == ExpressionType.Constant) { if (memberAssignment.Expression is ConstantExpression constantExpression) propertyValue = constantExpression.Value; } else { propertyValue = Expression.Lambda(memberAssignment.Expression, ).Compile().DynamicInvoke(); }
                      if (propertyName != _keyField) { fieldList.Add(Builders<TEntity>.Update.Set(propertyName, propertyValue)); } } }
                      if (session == ) await _dbSet.UpdateOneAsync(expression, Builders<TEntity>.Update.Combine(fieldList)); else await _dbContext.AddCommandAsync(async (session) => await _dbSet.UpdateOneAsync(expression, Builders<TEntity>.Update.Combine(fieldList))); }
                      public async Task UpdateAsync(FilterDefinition<TEntity> filter, UpdateDefinition<TEntity> update, IClientSessionHandle session = ) { if (session == ) await _dbSet.UpdateOneAsync(filter, update); else await _dbContext.AddCommandAsync(async (session) => await _dbSet.UpdateOneAsync(filter, update)); }
                      public async Task UpdateManyAsync(Expression<Func<TEntity, bool>> expression, UpdateDefinition<TEntity> update, IClientSessionHandle session = ) { if (session == ) await _dbSet.UpdateManyAsync(expression, update); else await _dbContext.AddCommandAsync(async (session) => await _dbSet.UpdateManyAsync(expression, update)); }
                      public async Task<UpdateResult> UpdateManayAsync(Dictionary<string, string> dic, FilterDefinition<TEntity> filter, IClientSessionHandle session = ) { var t = new TEntity(); // Fields to be updated var list = new List<UpdateDefinition<TEntity>>(); foreach (var item in t.GetType().GetProperties()) { if (!dic.ContainsKey(item.Name)) continue; var value = dic[item.Name]; list.Add(Builders<TEntity>.Update.Set(item.Name, value)); } var updatefilter = Builders<TEntity>.Update.Combine(list);
                      if (session == ) return await _dbSet.UpdateManyAsync(filter, updatefilter);
                      await _dbContext.AddCommandAsync(async (session) => await _dbSet.UpdateManyAsync(filter, updatefilter)); return new UpdateResult.Acknowledged(10, 10, ); }
                      #endregion
                      #region Read Part
                      public async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> expression, bool readFromPrimary = true) { var readPreference = GetReadPreference(readFromPrimary); var queryData = await _dbSet.WithReadPreference(readPreference) .Find(expression) .FirstOrDefaultAsync(); return queryData; }
                      public async Task<TEntity> GetAsync(string id, bool readFromPrimary = true) { var readPreference = GetReadPreference(readFromPrimary); var queryData = await _dbSet.WithReadPreference(readPreference).FindAsync(Builders<TEntity>.Filter.Eq(_keyField, new ObjectId(id))); return queryData.FirstOrDefault(); }
                      public async Task<IEnumerable<TEntity>> GetAllAsync(bool readFromPrimary = true) { var readPreference = GetReadPreference(readFromPrimary); var queryAllData = await _dbSet.WithReadPreference(readPreference).FindAsync(Builders<TEntity>.Filter.Empty); return queryAllData.ToList(); }
                      public async Task<long> CountAsync(Expression<Func<TEntity, bool>> expression, bool readFromPrimary = true) { var readPreference = GetReadPreference(readFromPrimary); return await _dbSet.WithReadPreference(readPreference).CountDocumentsAsync(expression); }
                      public async Task<long> CountAsync(FilterDefinition<TEntity> filter, bool readFromPrimary = true) { var readPreference = GetReadPreference(readFromPrimary); return await _dbSet.WithReadPreference(readPreference).CountDocumentsAsync(filter); }
                      public async Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate, bool readFromPrimary = true) { var readPreference = GetReadPreference(readFromPrimary); return await Task.FromResult(_dbSet.WithReadPreference(readPreference).AsQueryable().Any(predicate)); }
                      public async Task<List<TEntity>> FindListAsync(FilterDefinition<TEntity> filter, string[]? field = , SortDefinition<TEntity>? sort = , bool readFromPrimary = true) { var readPreference = GetReadPreference(readFromPrimary); if (field == || field.Length == 0) { if (sort == ) return await _dbSet.WithReadPreference(readPreference).Find(filter).ToListAsync();
                      return await _dbSet.WithReadPreference(readPreference).Find(filter).Sort(sort).ToListAsync(); }
                      var fieldList = new List<ProjectionDefinition<TEntity>>(); for (int i = 0; i < field.Length; i++) { fieldList.Add(Builders<TEntity>.Projection.Include(field[i].ToString())); } var projection = Builders<TEntity>.Projection.Combine(fieldList); fieldList?.Clear();
                      if (sort == ) return await _dbSet.WithReadPreference(readPreference).Find(filter).Project<TEntity>(projection).ToListAsync();
                      return await _dbSet.WithReadPreference(readPreference).Find(filter).Sort(sort).Project<TEntity>(projection).ToListAsync(); }
                      public async Task<List<TEntity>> FindListByPageAsync(FilterDefinition<TEntity> filter, int pageIndex, int pageSize, string[]? field = , SortDefinition<TEntity>? sort = , bool readFromPrimary = true) { var readPreference = GetReadPreference(readFromPrimary); if (field == || field.Length == 0) { if (sort == ) return await _dbSet.WithReadPreference(readPreference).Find(filter).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();
                      return await _dbSet.WithReadPreference(readPreference).Find(filter).Sort(sort).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync(); }
                      var fieldList = new List<ProjectionDefinition<TEntity>>(); for (int i = 0; i < field.Length; i++) { fieldList.Add(Builders<TEntity>.Projection.Include(field[i].ToString())); } var projection = Builders<TEntity>.Projection.Combine(fieldList); fieldList?.Clear();
                      if (sort == ) return await _dbSet.WithReadPreference(readPreference).Find(filter).Project<TEntity>(projection).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();
                      return await _dbSet.WithReadPreference(readPreference).Find(filter).Sort(sort).Project<TEntity>(projection).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync(); }
                      #endregion
                      #region Protected Methods
                      protected ReadPreference GetReadPreference(bool readFromPrimary) { if (readFromPrimary) return ReadPreference.PrimaryPreferred; else return ReadPreference.SecondaryPreferred; }
                      #endregion}

                      工作單元:UnitOfWork

                      在實(shí)際項(xiàng)目中,在對(duì)多個(gè)Repository操作之后,我們希望有一個(gè)統(tǒng)一的提交操作來(lái)實(shí)現(xiàn)事務(wù)的原子性。因此,我們可以有一個(gè)UnitOfWork來(lái)作為代理:

                      • public class UnitOfWork : IUnitOfWork{ private readonly IMongoDbContext _context;
                        public UnitOfWork(IMongoDbContext context) { _context = context; }
                        public bool SaveChanges(IClientSessionHandle session) { return _context.Commit(session) > 0; }
                        public async Task<bool> SaveChangesAsync(IClientSessionHandle session) { return await _context.CommitAsync(session) > 0; }
                        public IClientSessionHandle BeginTransaction() { return _context.StartSession(); }
                        public async Task<IClientSessionHandle> BeginTransactionAsync() { return await _context.StartSessionAsync(); }
                        public void Dispose() { _context.Dispose(); }}

                        封裝注入:ServiceCollectionExtensions

                        為了便于應(yīng)用中快速注入,我們可以簡(jiǎn)單封裝一個(gè)擴(kuò)展方法,快速注入相關(guān)的核心組成部分:

                        • public static class ServiceCollectionExtensions{ /// <summary> /// MongoDB Config Injection /// </summary> public static IServiceCollection AddMongoProxy(this IServiceCollection services, IConfiguration configuration) { if (!configuration.GetSection(nameof(MongoDatabaseConfigs)).Exists()) return services;
                          services.Configure<MongoDatabaseConfigs>(configuration.GetSection(nameof(MongoDatabaseConfigs))); services.AddSingleton(sp => sp.GetRequiredService<IOptions<MongoDatabaseConfigs>>().Value); services.AddSingleton<IMongoDbConnection, MongoDbConnection>(); services.AddScoped<IMongoDbContext, MongoDbContext>(); services.AddScoped<IUnitOfWork, UnitOfWork>();
                          return services; }}

                          如何使用:三步上籃

                          第一步:注入MongoProxy核心部分

                          在appsettings中配置MongoDB的連接信息:

                          • "MongoDatabaseConfigs": { "Servers": "xxx01.edisontalk.net,xxx02.edisontalk.net,xxx03.edisontalk.net", "Port": 27017, "ReplicaSetName": "edt-replica", "DatabaseName": "EDT_Practices", "UserName": "xxxxxxxxxxxxx", "Password": "xxxxxxxxxxxxx"}

                            然后通過(guò)擴(kuò)展方法注入MongoProxy相關(guān)部分:

                            builder.Services.AddMongoProxy(builder.Configuration);

                            第二步:添加Entity 和 Repository

                            示例Entity:

                            • [Table("Orders")]public class OrderEntity : MongoEntityBase, IEntity{ public string OrderNumber { get; set; } public List<TransmissionEntity> Transmissions { get; set; }}

                              示例Repository:

                              • public interface ITodoItemRepository : IMongoRepositoryBase<TodoItem>{}
                                public class TodoItemRepository : MongoRepositoryBase<TodoItem>, ITodoItemRepository{ public TodoItemRepository(IMongoDbContext mongoDbContext) : base(mongoDbContext) { }}
                                services.AddScoped<ITodoItemRepository, TodoItemRepository>();services.AddScoped<IOrderRepository, OrderRepository>();

                                第三步:使用Repository 和 UnitOfWork

                                • # 非事務(wù)模式await _taskRepository.AddManyAsync(newTasks);# 事務(wù)模式(借助UnitOfWork工作單元)private readonly IUnitOfWork _unitOfWork;
                                  public OrderService(IUnitOfWork unitOfWork, ......){ _unitOfWork = unitOfWork; ......}
                                  public async Task Example(){ using var session = await _unitOfWork.BeginTransactionAsync()) await _taskRepository.AddManyAsync(newTasks, session); await _orderRepository.AddAsync(newOrder, session);
                                  await _unitOfWork.SaveChangesAsync(session);}

                                  小結(jié)

                                  本文介紹了MongoDB事務(wù)的基本概念和如何通過(guò).NET操作事務(wù),重點(diǎn)介紹了EDT.MongoProxy這個(gè)小組件的設(shè)計(jì),讓我們可以在ASP.NET 6應(yīng)用中通過(guò)數(shù)據(jù)倉(cāng)儲(chǔ)(Repository)和工作單元(UnitOfWork)的模式來(lái)快速方便地操作MongoDB的事務(wù)。

                                  參考代碼

                                  本文代碼并未提供所有的,如需查看,請(qǐng)至下面的代碼倉(cāng)庫(kù)中查看,也可以點(diǎn)個(gè)贊給點(diǎn)鼓勵(lì)。

                                  GitHub:https://github.com/Coder-EdisonZhou/EDT.MongoProxy

                                  參考資料

                                  追逐時(shí)光者,《.NET Core MongoDB數(shù)據(jù)倉(cāng)儲(chǔ)和工作單元實(shí)操》:https://www.cnblogs.com/Can-daydayup/p/17157135.html

                                  *本文主要設(shè)計(jì)參考自這篇文章,值得一讀!

                                  TheCodeBuzz,《MongoDB Repository Implementation in .NET Core》:

                                  https://www.thecodebuzz.com/mongodb-repository-implementation-unit-testing-net-core-example

                                  Bryan Avery, 《ASP.NET Core - MongoDB Repository Pattern & Unit Of Work》:

                                  https://bryanavery.co.uk/asp-net-core-mongodb-repository-pattern-unit-of-work

                                  年終總結(jié):Edison的2022年終總結(jié)
                                  數(shù)字化轉(zhuǎn)型:我在傳統(tǒng)企業(yè)做數(shù)字化轉(zhuǎn)型
                                  C#刷題:C#刷劍指Offer算法題系列文章目錄
                                  .NET面試:.NET開發(fā)面試知識(shí)體系
                                  .NET大會(huì):2020年中國(guó).NET開發(fā)者大會(huì)PDF資料

          主站蜘蛛池模板: 国产99久久精品一区二区| 中文字幕亚洲一区| 亚洲一区影音先锋色资源| 在线播放国产一区二区三区 | 国产成人精品日本亚洲专一区 | 日韩一区二区三区在线| 亚洲一区二区影视| 好吊妞视频一区二区| 国产福利一区二区三区在线视频| 一区二区中文字幕在线观看| 色多多免费视频观看区一区| 国产成人一区二区在线不卡 | 日韩一区二区三区在线精品| a级午夜毛片免费一区二区| 色综合视频一区二区三区| 国产乱码精品一区三上| 福利片福利一区二区三区| 国产福利一区视频| 精品一区二区三区免费毛片| 午夜无码视频一区二区三区| 天码av无码一区二区三区四区| 制服美女视频一区| 精品性影院一区二区三区内射| 91一区二区三区四区五区| 国产主播福利一区二区| 无码人妻精品一区二区三区不卡 | 无码中文人妻在线一区二区三区| 波多野结衣一区在线观看| 天天看高清无码一区二区三区 | 一区二区在线电影| 亚洲一区二区三区无码影院| 午夜福利无码一区二区| 国精品无码一区二区三区在线| 久久免费区一区二区三波多野| 韩国精品一区二区三区无码视频| 日本精品一区二区久久久| 色噜噜AV亚洲色一区二区| 蜜桃臀无码内射一区二区三区| 夜夜爽一区二区三区精品| 鲁丝片一区二区三区免费| 精品国产伦一区二区三区在线观看 |