From a7233c192605ae89a78abe895c0d4e8eacc7fca2 Mon Sep 17 00:00:00 2001
From: 2881099 <2881099@qq.com>
Date: Thu, 8 Jun 2023 18:35:49 +0800
Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20FreeSqlBuilder=20UseAd?=
=?UTF-8?q?oConnectionPool=20=E6=9B=B4=E6=8D=A2=E8=BF=9E=E6=8E=A5=E6=B1=A0?=
=?UTF-8?q?=E6=96=B9=E6=A1=88=EF=BC=9B#1524=20#1343=20#1283=20#755?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Examples/base_entity/Program.cs | 8 +-
FreeSql/FreeSql.xml | 554 ++++++++++--------
FreeSql/FreeSqlBuilder.cs | 24 +-
.../CommonProvider/AdoProvider/AdoProvider.cs | 1 +
.../AdoProvider/DbConnectionPool.cs | 73 ++-
.../ClickHouseAdo/ClickHouseAdo.cs | 28 +-
.../DamengAdo/DamengAdo.cs | 23 +-
.../FirebirdAdo/FirebirdAdo.cs | 24 +-
.../GBaseAdo/GBaseAdo.cs | 24 +-
.../KingbaseESAdo/KingbaseESAdo.cs | 25 +-
.../MsAccessAdo/MsAccessAdo.cs | 23 +-
.../MySqlAdo/MySqlAdo.cs | 24 +-
.../Dameng/OdbcDamengAdo/OdbcDamengAdo.cs | 23 +-
.../Default/OdbcAdo/OdbcAdo.cs | 24 +-
.../OdbcKingbaseESAdo/OdbcKingbaseESAdo.cs | 24 +-
.../MySql/OdbcMySqlAdo/OdbcMySqlAdo.cs | 24 +-
.../Oracle/OdbcOracleAdo/OdbcOracleAdo.cs | 24 +-
.../OdbcPostgreSQLAdo/OdbcPostgreSQLAdo.cs | 24 +-
.../OdbcSqlServerAdo/OdbcSqlServerAdo.cs | 23 +-
.../OracleAdo/OracleAdo.cs | 23 +-
.../OracleAdo/OracleConnectionPool.cs | 12 +-
.../PostgreSQLAdo/PostgreSQLAdo.cs | 24 +-
.../QuestDbAdo/QuestDbAdo.cs | 24 +-
.../ShenTongAdo/ShenTongAdo.cs | 25 +-
.../SqlServerAdo/SqlServerAdo.cs | 23 +-
.../SqliteAdo/SqliteAdo.cs | 24 +-
.../SqliteAdo/SqliteConnectionPool.cs | 22 +-
.../FreeSql.Provider.Xugu/XuguAdo/XuguAdo.cs | 22 +-
28 files changed, 746 insertions(+), 450 deletions(-)
diff --git a/Examples/base_entity/Program.cs b/Examples/base_entity/Program.cs
index b08598d3..60e0955f 100644
--- a/Examples/base_entity/Program.cs
+++ b/Examples/base_entity/Program.cs
@@ -552,7 +552,7 @@ namespace base_entity
.UseNoneCommandParameter(true)
.UseNameConvert(NameConvertType.ToLower)
//.UseMappingPriority(MappingPriorityType.Attribute, MappingPriorityType.FluentApi, MappingPriorityType.Aop)
-
+ .UseAdoConnectionPool(true)
.UseConnectionString(FreeSql.DataType.Sqlite, "data source=:memory:")
.UseConnectionString(DataType.Sqlite, "data source=C:\\Users\\28810\\Desktop\\github\\FreeSql\\Examples\\base_entity\\AspNetRoleClaims\\ids_api.db")
@@ -568,9 +568,9 @@ namespace base_entity
//.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=3;TrustServerCertificate=true")
- .UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=2")
- //.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=toc;Pooling=true;Maximum Pool Size=2")
- .UseNameConvert(FreeSql.Internal.NameConvertType.ToLower)
+ //.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=2")
+ ////.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=toc;Pooling=true;Maximum Pool Size=2")
+ //.UseNameConvert(FreeSql.Internal.NameConvertType.ToLower)
//.UseConnectionString(FreeSql.DataType.Oracle, "user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2")
//.UseNameConvert(FreeSql.Internal.NameConvertType.ToUpper)
diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml
index 168bf8af..3b8168db 100644
--- a/FreeSql/FreeSql.xml
+++ b/FreeSql/FreeSql.xml
@@ -1358,6 +1358,19 @@
提供者的类型,一般不需要指定,如果一直提示“缺少 FreeSql 数据库实现包:FreeSql.Provider.MySql.dll,可前往 nuget 下载”的错误,说明反射获取不到类型,此时该参数可排上用场例如:typeof(FreeSql.SqlServer.SqlServerProvider<>)
+
+
+ 使用原始连接池(ado.net、odbc、oledb)
+ 默认:false
+ UseConnectionString 默认使用 FreeSql 连接池,有以下特点:
+ - 状态不可用,断熔机制直到后台检测恢复
+ - 读写分离,从库不可用,会切换其他可用从库
+ - 监测连接池使用情况,fsql.Ado.Statistics
+ 有部分使用者不喜欢【断熔机制】,可使用此设置
+
+
+
+
使用从数据库,支持多个
@@ -3537,177 +3550,6 @@
-
-
- 测试数据库是否连接正确,本方法执行如下命令:
- MySql/SqlServer/PostgreSQL/达梦/人大金仓/神通: SELECT 1
- Oracle: SELECT 1 FROM dual
-
- 命令超时设置(秒)
-
- true: 成功, false: 失败
-
-
-
- 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
-
-
-
-
-
-
-
-
-
- 查询,ExecuteReaderAsync(dr => {}, "select * from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 查询
-
-
-
-
-
-
-
-
- 查询,ExecuteArrayAsync("select * from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 查询
-
-
-
-
-
-
-
-
- 查询,ExecuteDataSetAsync("select * from user where age > @age; select 2", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 查询
-
-
-
-
-
-
-
-
- 查询,ExecuteDataTableAsync("select * from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 在【主库】执行
-
-
-
-
-
-
-
-
- 在【主库】执行,ExecuteNonQueryAsync("delete from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 在【主库】执行
-
-
-
-
-
-
-
-
- 在【主库】执行,ExecuteScalarAsync("select 1 from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
- 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new SqlParameter { ParameterName = "age", Value = 25 })
-
-
-
-
-
-
-
-
-
-
- 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
-
- 执行SQL返回对象集合,Query<User>("select * from user where age > @age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 })
-
-
-
-
-
-
-
-
-
-
-
- 执行SQL返回对象集合,Query<User, Address>("select * from user where age > @age; select * from address", new { age = 25 })
- 提示:parms 参数还可以传 Dictionary<string, object>
-
-
-
-
-
-
-
-
可自定义解析表达式
@@ -4698,12 +4540,6 @@
超时
-
-
- 获取资源
-
-
-
使用完毕后,归还资源
@@ -4779,12 +4615,6 @@
资源对象
-
-
- 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象
-
- 资源对象
-
归还对象给对象池的时候触发
@@ -5102,142 +4932,204 @@
- {tb2DbName}.{mp2MemberName} 被忽略,请检查 IsIgnore 设置,确认 get/set 为 public
+ {tb2DbName}.{mp2MemberName} 被忽略,请检查 IsIgnore 设"M:FreeSql.Internal.ObjectPool.IPolicy`1.OnCheckAvailable(FreeSql.Internal.ObjectPool.Object{`0})">
+
+ 检查可用性
+
+ 资源对象
+
+
+
+
+ 事件:可用时触发
-
+
- Include 参数类型错误
+ 事件:不可用时触发
-
+
- Include 参数类型错误,集合属性请使用 IncludeMany
+ 所属对象池
-
+
- Include 参数类型错误,表达式类型应该为 MemberAccess
+ 在对象池中的唯一标识
-
+
- IncludeMany 类型 {tbTypeDisplayCsharp} 的属性 {collMemMemberName} 不是有效的导航属性,提示:IsIgnore = true 不会成为导航属性
+ 资源对象
-
+
- IncludeMany {navigateSelector} 参数错误,Select 只可以使用一个参数的方法,正确格式:.Select(t =>new TNavigate {{}})
+ 被获取的总次数
-
+
+ 最后获取时的时间
+
+
- IncludeMany {navigateSelector} 参数错误,Select lambda参数返回值必须和 {collMemElementType} 类型一致
+ 最后归还时的时间
-
+
- IncludeMany 参数1 类型错误,表达式类型应该为 MemberAccess
+ 创建时间
-
+
- IncludeMany {navigateSelector} 参数类型错误,正确格式: a.collections.Take(1).Where(c =>c.aid == a.id).Select(a=> new TNavigate{{}})
+ 最后获取时的线程id
-
+
- ISelect.InsertInto() 未选择属性: {displayCsharp}
+ 最后归还时的线程id
-
+
- ISelect.InsertInto() 类型错误: {displayCsharp}
+ 重置 Value 值
-
+
- InsertOrUpdate 功能执行 merge into 要求实体类 {CsName} 必须有主键
+ 对象池管理类
+
+ 对象类型
+
+
+
+ 后台定时检查可用性
+
+
+
+
+
+ 创建对象池
+
+ 池大小
+ 池内对象的创建委托
+ 获取池内对象成功后,进行使用前操作
+
+
+
+ 创建对象池
+
+ 策略
+
+
+
+ 获取可用资源,或创建资源
+
+
+
+
+
+
+ String resources used in FreeSql exceptions, etc.
+
+
+ These strings are exposed publicly for use by database providers and extensions.
+ It is unusual for application code to need these strings.
+
-
+
- InsertOrUpdate<>的泛型参数 不支持 {typeofT1},请传递您的实体类
+ 重写当前线程的 CurrentUICulture 属性,对
+ 使用此强类型资源类的所有资源查找执行重写。
-
+
- 【延时加载】功能需要安装 FreeSql.Extensions.LazyLoading.dll,可前往 nuget 下载
+ [Table(AsTable = "{asTable}")] 特性值格式错误
-
+
- 【延时加载】{trytbTypeName} 编译错误:{exMessage}\r\n\r\n{cscode}
+ [Table(AsTable = xx)] 设置的属性名 {atmGroupsValue} 不是 DateTime 类型
-
+
- 【延时加载】实体类型 {trytbTypeName} 必须声明为 public
+ {name}: Failed to get resource {statistics}
-
+
- ManyToMany 导航属性 .AsSelect() 暂时不可用于 Sum/Avg/Max/Min/First/ToOne/ToList 方法
+ {name}: An exception needs to be thrown
-
+
- 【ManyToMany】导航属性 {trytbTypeName}.{pnvName} 在 {tbmidCsName} 中没有找到对应的字段,如:{midTypePropsTrytbName}{findtrytbPkCsName}、{midTypePropsTrytbName}_{findtrytbPkCsName}
+ 错误的表达式格式 {column}
-
+
- 【ManyToMany】导航属性 {trytbTypeName}.{pnvName} 解析错误,实体类型 {tbrefTypeName} 缺少主键标识,[Column(IsPrimary = true)]
+ Chunk 功能之前不可使用 Select
-
+
- 【ManyToMany】导航属性 {trytbTypeName}.{pnvName} 解析错误,实体类型 {tbrefTypeName} 必须存在对应的 [Navigate(ManyToMany = x)] 集合属性
+ 安全起见,请务必在事务开启之后,再使用 ForUpdate
-
+
- 【ManyToMany】导航属性 {trytbTypeName}.{pnvName} 解析错误,{tbmidCsName}.{trycolCsName} 和 {trytbCsName}.{trytbPrimarysCsName} 类型不一致
+ 不能为 null
-
+
- 【ManyToMany】导航属性 {trytbTypeName}.{pnvName} 解析错误,中间类 {tbmidCsName}.{midTypePropsTrytbName} 错误:{exMessage}
+ {name} 不能为 null
-
+
- 【ManyToMany】导航属性 {trytbTypeName}.{pnvName} 解析错误,中间类 {tbmidCsName}.{midTypePropsTrytbName} 导航属性不是【ManyToOne】或【OneToOne】
+ 无法匹配 {property}
-
+
- 映射异常:{name} 没有一个属性名相同
+ {property} 无法解析为表达式树
-
+
- Ado.MasterPool 值为 null,该操作无法自启用事务,请显式传递【事务对象】解决
+ 参数 masterConnectionString 不可为空,请检查 UseConnectionString
-
+
- 缺少 FreeSql 数据库实现包:FreeSql.Provider.{Provider}.dll,可前往 nuget 下载
+ 提交
-
+
- 缺少 FreeSql 数据库实现包:{dll},可前往 nuget 下载;如果存在 {dll} 依然报错(原因是环境问题导致反射不到类型),请在 UseConnectionString/UseConnectionFactory 第三个参数手工传入 typeof({providerType})
+ 连接失败,准备切换其他可用服务器
-
+
- 导航属性 {trytbTypeName}.{pnvName} 特性 [Navigate] Bind 数目({bindColumnsCount}) 与 外部主键数目({tbrefPrimarysLength}) 不相同
+ 自定义表达式解析错误:类型 {exp3MethodDeclaringType} 需要定义 static ThreadLocal<ExpressionCallContext> 字段、字段、字段(重要三次提醒)
+
+
+
+
+ Custom { 反射信息 }不能为空,格式:{ 静态方法名 }{ 空格 }{ 反射信息 }
+
+
+
+
+ Custom { 静态方法名 }不能为空,格式:{ 静态方法名 }{ 空格 }{ 反射信息 }
+ 目({tbrefPrimarysLength}) 不相同
@@ -6226,7 +6118,191 @@
-`0})">
+
+
+
+ 使用 and 拼接两个 lambda 表达式
+
+
+ true 时生效
+
+
+
+
+
+ 使用 or 拼接两个 lambda 表达式
+
+
+
+
+
+ 使用 or 拼接两个 lambda 表达式
+
+
+ true 时生效
+
+
+
+
+
+ 将 lambda 表达式取反
+
+
+ true 时生效
+
+
+
+
+ 使用 and 拼接两个 lambda 表达式
+
+
+
+
+
+ 使用 and 拼接两个 lambda 表达式
+
+
+ true 时生效
+
+
+
+
+
+ 使用 or 拼接两个 lambda 表达式
+
+
+
+
+
+ 使用 or 拼接两个 lambda 表达式
+
+
+ true 时生效
+
+
+
+
+
+ 将 lambda 表达式取反
+
+
+ true 时生效
+
+
+
+
+ 使用 and 拼接两个 lambda 表达式
+
+
+
+
+
+ 使用 and 拼接两个 lambda 表达式
+
+
+ true 时生效
+
+
+
+
+
+ 使用 or 拼接两个 lambda 表达式
+
+
+
+
+
+ 使用 or 拼接两个 lambda 表达式
+
+
+ true 时生效
+
+
+
+
+
+ 将 lambda 表达式取反
+
+
+ true 时生效
+
+
+
+
+ 使用 and 拼接两个 lambda 表达式
+
+
+
+
+
+ 使用 and 拼接两个 lambda 表达式
+
+
+ true 时生效
+
+
+
+
+
+ 使用 or 拼接两个 lambda 表达式
+
+
+
+
+
+ 使用 or 拼接两个 lambda 表达式
+
+
+ true 时生效
+
+
+
+
+
+ 将 lambda 表达式取反
+
+
+ true 时生效
+
+
+
+
+ 生成类似Mongodb的ObjectId有序、不重复Guid
+
+
+
+
+
+ 插入数据
+
+
+
+
+
+
+ 插入数据,传入实体
+
+
+
+
+
+
+
+ 插入数据,传入实体数组
+
+
+
+
+
+
+
+ 插入数据,传入实体集合
+
+
+
+
+
+
插入数据,传入实体集合
diff --git a/FreeSql/FreeSqlBuilder.cs b/FreeSql/FreeSqlBuilder.cs
index 7aedbcac..97d28697 100644
--- a/FreeSql/FreeSqlBuilder.cs
+++ b/FreeSql/FreeSqlBuilder.cs
@@ -24,6 +24,7 @@ namespace FreeSql
bool _isLazyLoading = false;
bool _isExitAutoDisposePool = true;
bool _isQuoteSqlName = true;
+ bool _isAdoConnectionPool = false;
MappingPriorityType[] _mappingPriorityTypes;
NameConvertType _nameConvertType = NameConvertType.None;
Action _aopCommandExecuting = null;
@@ -46,6 +47,22 @@ namespace FreeSql
return this;
}
///
+ /// 使用原始连接池(ado.net、odbc、oledb)
+ /// 默认:false
+ /// UseConnectionString 默认使用 FreeSql 连接池,有以下特点:
+ /// - 状态不可用,断熔机制直到后台检测恢复
+ /// - 读写分离,从库不可用,会切换其他可用从库
+ /// - 监测连接池使用情况,fsql.Ado.Statistics
+ /// 有部分使用者不喜欢【断熔机制】,可使用此设置
+ ///
+ ///
+ ///
+ public FreeSqlBuilder UseAdoConnectionPool(bool value)
+ {
+ _isAdoConnectionPool = true;
+ return this;
+ }
+ ///
/// 使用从数据库,支持多个
///
/// 从数据库连接串
@@ -353,7 +370,12 @@ namespace FreeSql
default: throw new Exception(CoreStrings.NotSpecified_UseConnectionString_UseConnectionFactory);
}
}
- ret = Activator.CreateInstance(type, new object[] { _masterConnectionString, _slaveConnectionString, _connectionFactory }) as IFreeSql;
+ ret = Activator.CreateInstance(type, new object[]
+ {
+ _isAdoConnectionPool ? $"AdoConnectionPool,{_masterConnectionString}" : _masterConnectionString,
+ _slaveConnectionString,
+ _connectionFactory
+ }) as IFreeSql;
if (ret != null)
{
ret.CodeFirst.IsAutoSyncStructure = _isAutoSyncStructure;
diff --git a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs
index 2c018fde..7a39120e 100644
--- a/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs
+++ b/FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs
@@ -37,6 +37,7 @@ namespace FreeSql.Internal.CommonProvider
public AdoProvider(DataType dataType, string connectionString, string[] slaveConnectionStrings)
{
+ if (connectionString?.StartsWith("AdoConnectionPool,") == true) connectionString = connectionString.Substring("AdoConnectionPool,".Length);
this.DataType = dataType;
this.ConnectionString = connectionString;
this.SlaveConnectionStrings = slaveConnectionStrings;
diff --git a/FreeSql/Internal/CommonProvider/AdoProvider/DbConnectionPool.cs b/FreeSql/Internal/CommonProvider/AdoProvider/DbConnectionPool.cs
index d150efed..7dd3fa6c 100644
--- a/FreeSql/Internal/CommonProvider/AdoProvider/DbConnectionPool.cs
+++ b/FreeSql/Internal/CommonProvider/AdoProvider/DbConnectionPool.cs
@@ -44,7 +44,7 @@ namespace FreeSql.Internal.CommonProvider
_dataType = dataType;
_connectionFactory = connectionFactory;
- Policy = new DbConnectionPoolPolicy(this);
+ Policy = new DbConnectionPoolPolicy(dataType.ToString(), connectionFactory);
}
public IPolicy Policy { get; }
@@ -94,15 +94,74 @@ namespace FreeSql.Internal.CommonProvider
}
}
- internal class DbConnectionPoolPolicy : IPolicy
+ public class DbConnectionStringPool : IObjectPool
{
- DbConnectionPool Pool;
- public DbConnectionPoolPolicy(DbConnectionPool pool)
+ internal DataType _dataType;
+ internal Func _connectionFactory;
+ int _id;
+ public DbConnectionStringPool(DataType dataType, string name, Func connectionFactory)
{
- this.Pool = pool;
+ _dataType = dataType;
+ _connectionFactory = connectionFactory;
+ Policy = new DbConnectionPoolPolicy(string.IsNullOrWhiteSpace(name) ? dataType.ToString() : name, connectionFactory);
}
- public string Name { get; set; } = typeof(DbConnectionPoolPolicy).GetType().FullName;
+ public IPolicy Policy { get; }
+
+ public bool IsAvailable => true;
+ public Exception UnavailableException => null;
+ public DateTime? UnavailableTime => null;
+ public string Statistics => "throw new NotImplementedException()";
+ public string StatisticsFullily => "throw new NotImplementedException()";
+
+ public void Dispose()
+ {
+ }
+
+ public Object Get(TimeSpan? timeout = null)
+ {
+ var conn = _connectionFactory();
+ if (conn.State != ConnectionState.Open)
+ conn.Open();
+ return Object.InitWith(this, Interlocked.Increment(ref _id), conn);
+ }
+
+#if net40
+#else
+ async public Task