-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathSqlConnectionPool.cs
147 lines (116 loc) · 4.18 KB
/
SqlConnectionPool.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
using SafeObjectPool;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace System.Data.SqlClient {
public class SqlConnectionPool : ObjectPool<SqlConnection> {
internal Action availableHandler;
internal Action unavailableHandler;
public SqlConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null) {
var policy = new SqlConnectionPoolPolicy {
_pool = this,
Name = name
};
this.Policy = policy;
policy.ConnectionString = connectionString;
this.availableHandler = availableHandler;
this.unavailableHandler = unavailableHandler;
}
public void Return(Object<SqlConnection> obj, Exception exception, bool isRecreate = false) {
if (exception != null && exception is SqlException) {
if (obj.Value.Ping() == false) {
base.SetUnavailable(exception);
}
}
base.Return(obj, isRecreate);
}
}
public class SqlConnectionPoolPolicy : IPolicy<SqlConnection> {
internal SqlConnectionPool _pool;
public string Name { get; set; } = "SQLServer SqlConnection 对象池";
public int PoolSize { get; set; } = 100;
public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero;
public int AsyncGetCapacity { get; set; } = 10000;
public bool IsThrowGetTimeoutException { get; set; } = true;
public int CheckAvailableInterval { get; set; } = 5;
private string _connectionString;
public string ConnectionString {
get => _connectionString;
set {
_connectionString = value ?? "";
Match m = Regex.Match(_connectionString, @"Max\s*pool\s*size\s*=\s*(\d+)", RegexOptions.IgnoreCase);
if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100;
PoolSize = poolsize;
var initConns = new Object<SqlConnection>[poolsize];
for (var a = 0; a < poolsize; a++) try { initConns[a] = _pool.Get(); } catch { }
foreach (var conn in initConns) _pool.Return(conn);
}
}
public bool OnCheckAvailable(Object<SqlConnection> obj) {
if (obj.Value.State == ConnectionState.Closed) obj.Value.Open();
var cmd = obj.Value.CreateCommand();
cmd.CommandText = "select 1";
cmd.ExecuteNonQuery();
return true;
}
public SqlConnection OnCreate() {
var conn = new SqlConnection(_connectionString);
return conn;
}
public void OnDestroy(SqlConnection obj) {
if (obj.State != ConnectionState.Closed) obj.Close();
obj.Dispose();
}
public void OnGet(Object<SqlConnection> obj) {
if (_pool.IsAvailable) {
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false) {
try {
obj.Value.Open();
} catch (Exception ex) {
if (_pool.SetUnavailable(ex) == true)
throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
}
}
}
}
async public Task OnGetAsync(Object<SqlConnection> obj) {
if (_pool.IsAvailable) {
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false) {
try {
await obj.Value.OpenAsync();
} catch (Exception ex) {
if (_pool.SetUnavailable(ex) == true)
throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
}
}
}
}
public void OnGetTimeout() {
}
public void OnReturn(Object<SqlConnection> obj) {
if (obj.Value.State != ConnectionState.Closed) try { obj.Value.Close(); } catch { }
}
public void OnAvailable() {
_pool.availableHandler?.Invoke();
}
public void OnUnavailable() {
_pool.unavailableHandler?.Invoke();
}
}
public static class SqlConnectionExtensions {
public static bool Ping(this SqlConnection that) {
try {
var cmd = that.CreateCommand();
cmd.CommandText = "select 1";
cmd.ExecuteNonQuery();
return true;
} catch {
if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
return false;
}
}
}
}