.netcore implement a separate read and write database access middleware

Original: .netcore achieve a separate read and write database access middleware

In the real business system, when the single database can not carry load pressure, generally we use separate read and write database database load sharing manner. Bear the main library and write transaction operations, bear a read operation from the library.

In order to support a variety of database we first define a data type dictionary. a connection string for the key, value for the database type:

Copy the code
        /// <summary>
        /// 数据库方言集合
        /// </summary>
        private readonly Dictionary<string, DatabaseDialectEnum> DialectDictionary
          = new Dictionary<string, DatabaseDialectEnum>
          {
              ["sqlconnection"] = DatabaseDialectEnum.MSSQL,
              ["sqlceconnection"] = DatabaseDialectEnum.SQLCE,
              ["npgsqlconnection"] = DatabaseDialectEnum.POSTGRES,
              ["sqliteconnection"] = DatabaseDialectEnum.SQLLITE,
              ["mysqlconnection"] = DatabaseDialectEnum.MYSQL,
              ["fbconnection"] = DatabaseDialectEnum.FIREBASE
          };
Copy the code

We switch to a different database only need to configure the database connection string can be.

In mssql an example, the configuration database connection string

Copy the code
  "ConnectionString": {
    "sqlconnection": "Data Source=.;Initial Catalog=Db;User ID=sa;Password=**;Enlist=false;Max Pool SIZE=500;Min Pool SIZE=50;MultipleActiveResultSets=True",
    "sqlconnection_slaver_1": "Data Source=.;Initial Catalog=Db;User ID=sa;Password=**;Enlist=false;Max Pool SIZE=500;Min Pool SIZE=50;MultipleActiveResultSets=True",
    "sqlconnection_slaver_2": "Data Source=.;Initial Catalog=Db;User ID=sa;Password=**;Enlist=false;Max Pool SIZE=500;Min Pool SIZE=50;MultipleActiveResultSets=True"
  }
Copy the code
Key: sqlconnection primary library (master) connection string, Key: sqlconnection_slaver_1 sqlconnection_slaver_2 and two connection strings from the library (slaver). More from the library (slaver) random access can be achieved. Other algorithms can also be used for load balancing. 

The connection configuration string we get master database connection string, the connection string and set from the library. Simultaneously determining the type of the database according to the connection string Key . code show as below:

Copy the code
        ///  <Summary> 
        /// primary database connection string
         ///  </ Summary> 
        Private  String MasterConnectionString { GET ; SET ;}
         ///  <Summary> 
        /// from the database a set of strings
         ///  </ Summary> 
        Private List < String > SlaverConnectionStrings { GET ; SET ;} = new new List < String > ();
         public the ConnectionFactory (Configuration IConfiguration, ILoggerFactory LoggerFactory) 
        { 
            _logger= loggerFactory.CreateLogger<ConnectionFactory>();
            var connectionKeys = configuration.GetSection("ConnectionString").GetChildren().Select(s => s.Key).ToArray();
            foreach (var connKey in connectionKeys)
            {
                var connSplit = connKey.Split('_');
                if (connSplit.Length == 1)
                {
                    MasterConnectionString = configuration[$"ConnectionString:{connKey}"];
            // The connecting string agreed to determine the type of database DatabaseDialect
= DialectDictionary [connKey]; } the else { SlaverConnectionStrings.Add (Configuration [$ " the ConnectionString: connKey {} " ]); } } }
Copy the code
        ///  <Summary> 
        /// database type
         ///  </ Summary> 
        public DatabaseDialectEnum DatabaseDialect { GET ; Private  SET ;}

Get connected to the main library

        private IDbConnection GetMasterConnection()
        {
            return GetConnection(MasterConnectionString);
        }

Get the connection from the library, where the random algorithm, if no configuration from the library, this library will return to the main connection.

Copy the code
        Private the IDbConnection GetSlaverConnection () 
        { 
            int SC = SlaverConnectionStrings.Count ();
             IF (SC> 0 ) 
            { 
                the Random Random = new new the Random ();
                 int index = Random.Next ( 0 , SC);
                 return the GetConnection (SlaverConnectionStrings [index]) ; 
            } 
            the else 
            { 
                _logger.LogInformation ( " not set from the library, the library will establish the main connection " );
                 return GetMasterConnection (); 
            } 
        }    
Copy the code
Copy the code
        private IDbConnection GetConnection(string connectionString) => DatabaseDialect switch
        {
            DatabaseDialectEnum.MSSQL =>new ProfiledDbConnection(new SqlConnection(connectionString),MiniProfiler.Current),
            DatabaseDialectEnum.MYSQL => new ProfiledDbConnection(new MySqlConnection(connectionString), MiniProfiler.Current),
            _ => throw new NotImplementedException()
        };
Copy the code
NOTE: MiniProfiler used here to monitor the performance of the database connection, the connection was returned packaging ProfiledDbConnection.

Master from the data source types are as follows:

    public enum DataSourceEnum
    {
        MASTER,
        SLAVE
    }

ConnectionFactory present embodiment is a single mode, there is a case of multi-threaded access, so the data source is set to ThreadLocal <DataSourceEnum>, the threads share.

Copy the code
private static ThreadLocal<DataSourceEnum> threadLocal = new ThreadLocal<DataSourceEnum>();
        /// <summary>
        /// 当前线程数据源 
        /// </summary>
        /// <param name="sourceEnum"></param>     
        public DataSourceEnum DataSource
        {
            set { threadLocal.Value = value; }
            get { return threadLocal.Value; }
        }
Copy the code

The following formal acquisition IDbConnection

Copy the code
        public IDbConnection GetDbConnection()
        {
            if (DataSource == DataSourceEnum.MASTER)
            {
                return GetMasterConnection();
            }
            else
            {
                return GetSlaverConnection();
            }
        }
Copy the code

use:

According to the actual beginning of the article described the operation to be accessed from the main repository for.

        private IDbConnection GetDbConnection(DataSourceEnum dataSource)
        {
            ConnectionFactory.DataSource = dataSource;
            return ConnectionFactory.GetDbConnection();
        }
using var connection = GetDbConnection(DataSourceEnum.MASTER);
 connection.Execute(sql, param, CurrentTransaction, null, commandType)
 using var connection = GetDbConnection(DataSourceEnum.SLAVE);
 connection.Get<T>(id, CurrentTransaction, CommandTimeout)

 

Offer all the code

Copy the code
    public class ConnectionFactory : IConnectionFactory
    {
        private readonly ILogger _logger;
        private static ThreadLocal<DataSourceEnum> threadLocal = new ThreadLocal<DataSourceEnum>();
        static ConnectionFactory()
        {
            //设置dapper的tableName取值
            SqlMapperExtensions.TableNameMapper = (type) => type.Name;
        } 

        /// <summary>
        /// 当前线程数据源 
        /// </summary>
        /// <param name="sourceEnum"></param>     
        public DataSourceEnum DataSource
        { 
            SET {threadLocal.Value = value;}
             GET { return threadLocal.Value;} 
        } 

        ///  <Summary> 
        /// primary database connection string
         ///  </ Summary> 
        Private  String MasterConnectionString { GET ; SET ;}
         // /  <Summary> 
        /// from the database a set of strings
         ///  </ Summary> 
        Private List < String > SlaverConnectionStrings { GET ; sET ;} = new new List < String >();
        public ConnectionFactory(IConfiguration configuration, ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<ConnectionFactory>();
            var connectionKeys = configuration.GetSection("ConnectionString").GetChildren().Select(s => s.Key).ToArray();
            foreach (var connKey in connectionKeys)
            {
                var connSplit = connKey.Split('_');
                if (connSplit.Length == 1)
                {
                    MasterConnectionString = configuration[$"ConnectionString:{connKey}"];
                    DatabaseDialect = DialectDictionary[connKey];
                }
                else
                {
                    SlaverConnectionStrings.Add(configuration[$"ConnectionString:{connKey}"]);
                }

            }
        }
        /// <summary>
        /// 数据库方言集合
        /// </summary>
        private readonly Dictionary<string, DatabaseDialectEnum> DialectDictionary
          = new Dictionary<string, DatabaseDialectEnum>
          {
              ["sqlconnection"] = DatabaseDialectEnum.MSSQL,
              ["sqlceconnection"] = DatabaseDialectEnum.SQLCE,
              ["npgsqlconnection"] = DatabaseDialectEnum.POSTGRES,
              ["sqliteconnection"] = DatabaseDialectEnum.SQLLITE,
              ["mysqlconnection"] = DatabaseDialectEnum.MYSQL,
              ["fbconnection"] = DatabaseDialectEnum.FIREBASE
          };
        /// <summary>
        /// 数据库方言
        /// </summary>
        public DatabaseDialectEnum DatabaseDialect { get; private set; }

        private IDbConnection GetConnection(string connectionString) => DatabaseDialect switch
        {
            DatabaseDialectEnum.MSSQL =>new ProfiledDbConnection(new SqlConnection(connectionString),MiniProfiler.Current),
            DatabaseDialectEnum.MYSQL => new ProfiledDbConnection(new MySqlConnection(connectionString), MiniProfiler.Current),
            _ => throw new NotImplementedException()
        };
        public IDbConnection GetDbConnection()
        {
            if (DataSource == DataSourceEnum.MASTER)
            {
                return GetMasterConnection();
            }
            else
            {
                return GetSlaverConnection();
            }
        }
        private IDbConnection GetMasterConnection()
        {
            return GetConnection(MasterConnectionString);
        }
        private IDbConnection GetSlaverConnection()
        {
            int sc = SlaverConnectionStrings.Count();
            if (sc > 0)
            {
                Random random = new Random();
                int index = random.Next(0, sc);
                return GetConnection(SlaverConnectionStrings[index]);
            }
            else
            {
                _logger.LogInformation(" It is not provided from the library, from the library to establish the main connection " );
                 return GetMasterConnection (); 
            } 
        }     
    } 

    public  enum DataSourceEnum 
    { 
        the MASTER, 
        SLAVE 
    }
Copy the code

Guess you like

Origin www.cnblogs.com/lonelyxmas/p/12051882.html