diff --git a/Src/Asp.Net/SqlServerTest/Demos/A_MasterSlave.cs b/Src/Asp.Net/SqlServerTest/Demos/A_MasterSlave.cs new file mode 100644 index 000000000..943ea2a62 --- /dev/null +++ b/Src/Asp.Net/SqlServerTest/Demos/A_MasterSlave.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OrmTest.Demos +{ + public class MasterSlave + { + } +} diff --git a/Src/Asp.Net/SqlServerTest/SqlServerTest.csproj b/Src/Asp.Net/SqlServerTest/SqlServerTest.csproj index 92a38cddb..97fd5ea18 100644 --- a/Src/Asp.Net/SqlServerTest/SqlServerTest.csproj +++ b/Src/Asp.Net/SqlServerTest/SqlServerTest.csproj @@ -59,6 +59,7 @@ + diff --git a/Src/Asp.Net/SqlSugar/Abstract/AdoProvider/AdoProvider.cs b/Src/Asp.Net/SqlSugar/Abstract/AdoProvider/AdoProvider.cs index a0f96bc78..7c051139a 100644 --- a/Src/Asp.Net/SqlSugar/Abstract/AdoProvider/AdoProvider.cs +++ b/Src/Asp.Net/SqlSugar/Abstract/AdoProvider/AdoProvider.cs @@ -5,6 +5,7 @@ using System.Data.SqlClient; using System.Linq; using System.Reflection; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace SqlSugar { @@ -55,6 +56,8 @@ namespace SqlSugar public virtual Action LogEventCompleted { get; set; } public virtual Func> ProcessingEventStartingSQL { get; set; } public virtual Action ErrorEvent { get; set; } + public virtual List SlaveConnections { get; set; } + public virtual IDbConnection MasterConnection { get; set; } #endregion #region Connection @@ -230,6 +233,7 @@ namespace SqlSugar { try { + SetConnectionStart(sql); if (this.ProcessingEventStartingSQL != null) ExecuteProcessingSQL(ref sql, parameters); ExecuteBefore(sql, parameters); @@ -238,6 +242,7 @@ namespace SqlSugar if (this.IsClearParameters) sqlCommand.Parameters.Clear(); ExecuteAfter(sql, parameters); + SetConnectionEnd(); return count; } catch (Exception ex) @@ -255,6 +260,7 @@ namespace SqlSugar { try { + SetConnectionStart(sql); var isSp = this.CommandType == CommandType.StoredProcedure; if (this.ProcessingEventStartingSQL != null) ExecuteProcessingSQL(ref sql, parameters); @@ -266,6 +272,7 @@ namespace SqlSugar if (this.IsClearParameters) sqlCommand.Parameters.Clear(); ExecuteAfter(sql, parameters); + SetConnectionEnd(); return sqlDataReader; } catch (Exception ex) @@ -279,6 +286,7 @@ namespace SqlSugar { try { + SetConnectionStart(sql); if (this.ProcessingEventStartingSQL != null) ExecuteProcessingSQL(ref sql, parameters); ExecuteBefore(sql, parameters); @@ -290,6 +298,7 @@ namespace SqlSugar if (this.IsClearParameters) sqlCommand.Parameters.Clear(); ExecuteAfter(sql, parameters); + SetConnectionEnd(); return ds; } catch (Exception ex) @@ -307,6 +316,7 @@ namespace SqlSugar { try { + SetConnectionStart(sql); if (this.ProcessingEventStartingSQL != null) ExecuteProcessingSQL(ref sql, parameters); ExecuteBefore(sql, parameters); @@ -316,6 +326,7 @@ namespace SqlSugar if (this.IsClearParameters) sqlCommand.Parameters.Clear(); ExecuteAfter(sql, parameters); + SetConnectionEnd(); return scalar; } catch (Exception ex) @@ -650,6 +661,48 @@ namespace SqlSugar { return this.Context.CurrentConnectionConfig.IsAutoCloseConnection && this.Transaction == null; } + private bool IsMasterSlaveSeparation + { + get + { + return this.Context.CurrentConnectionConfig.SlaveConnectionStrings.HasValue(); + } + } + private void SetConnectionStart(string sql) + { + if (this.IsMasterSlaveSeparation&&IsRead(sql)) + { + if (this.MasterConnection == null) + { + this.MasterConnection = this.Connection; + } + var saves = this.Context.CurrentConnectionConfig.SlaveConnectionStrings.Where(it => it.HitRate > 0).ToList(); + var currentIndex = UtilRandom.GetRandomIndex(saves.ToDictionary(it => saves.ToList().IndexOf(it), it => it.HitRate)); + var currentSaveConnection = saves[currentIndex]; + this.Connection = null; + this.Context.CurrentConnectionConfig.ConnectionString = currentSaveConnection.ConnectionString; + var connection = this.SlaveConnections.FirstOrDefault(it => it.ToString() == currentSaveConnection.ConnectionString); + if (connection == null) + { + this.SlaveConnections.Add(this.Connection); + } + } + } + private void SetConnectionEnd() + { + if (this.IsMasterSlaveSeparation) + { + this.Connection = this.MasterConnection; + this.Context.CurrentConnectionConfig.ConnectionString = this.MasterConnection.ToString(); + } + } + + private bool IsRead(string sql) + { + var sqlLower = sql.ToLower(); + var result = Regex.IsMatch(sqlLower, "[ ]*select[ ]") && !Regex.IsMatch(sqlLower, "[ ]*insert[ ]|[ ]*update[ ]|[ ]*delete[ ]"); + return result; + } #endregion } } diff --git a/Src/Asp.Net/SqlSugar/Entities/ConnectionConfig.cs b/Src/Asp.Net/SqlSugar/Entities/ConnectionConfig.cs index 31e25eb64..566b0991c 100644 --- a/Src/Asp.Net/SqlSugar/Entities/ConnectionConfig.cs +++ b/Src/Asp.Net/SqlSugar/Entities/ConnectionConfig.cs @@ -28,6 +28,11 @@ namespace SqlSugar /// public ConfigureExternalServices ConfigureExternalServices = _DefaultServices; private static ConfigureExternalServices _DefaultServices = new ConfigureExternalServices(); + /// + /// If SlaveConnectionStrings has value,ConnectionString is write operation, SlaveConnectionStrings is read operation. + /// All operations within a transaction is ConnectionString + /// + public List SlaveConnectionStrings { get; set; } } public class ConfigureExternalServices diff --git a/Src/Asp.Net/SqlSugar/Entities/SlaveConnectionConfig.cs b/Src/Asp.Net/SqlSugar/Entities/SlaveConnectionConfig.cs new file mode 100644 index 000000000..b0d3e6497 --- /dev/null +++ b/Src/Asp.Net/SqlSugar/Entities/SlaveConnectionConfig.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SqlSugar +{ + public class SlaveConnectionConfig + { + /// + ///Default value is 1 + ///If value is 0 means permanent non execution + /// + public int HitRate = 1; + public string ConnectionString { get; set; } + } +} diff --git a/Src/Asp.Net/SqlSugar/SqlSugar.csproj b/Src/Asp.Net/SqlSugar/SqlSugar.csproj index efe4d41f2..96bc013a6 100644 --- a/Src/Asp.Net/SqlSugar/SqlSugar.csproj +++ b/Src/Asp.Net/SqlSugar/SqlSugar.csproj @@ -76,6 +76,7 @@ + @@ -170,6 +171,7 @@ + diff --git a/Src/Asp.Net/SqlSugar/Utilities/UtilRandom.cs b/Src/Asp.Net/SqlSugar/Utilities/UtilRandom.cs new file mode 100644 index 000000000..916fb47e8 --- /dev/null +++ b/Src/Asp.Net/SqlSugar/Utilities/UtilRandom.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SqlSugar +{ + public class UtilRandom + { + public static Random Random = new Random(); + public static int GetRandomIndex(Dictionary pars) + { + int maxValue = 0; + foreach (var item in pars) + { + maxValue = +item.Value; + } + var num = Random.Next(1, maxValue); + var result = 0; + var endValue = 0; + foreach (var item in pars) + { + var index = pars.ToList().IndexOf(item); + var beginValue = index == 0 ? 0 : pars[index - 1]; + endValue += item.Value; + result = item.Key; + if (num >= beginValue && num <= endValue) + break; + } + return result; + } + } +}