├── .gitattributes
├── .gitignore
├── DriveTest
├── App.config
├── BatcherTest.cs
├── DemoModel.cs
├── DriveTest.csproj
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── packages.config
├── LICENSE
├── README.md
├── RedisDrive.sln
├── VisualStudio.gitignore
├── Wenli.Drive.Redis
├── App.config
├── Core
│ ├── RedisBatcher.cs
│ ├── RedisConnection.cs
│ ├── SERedisConnection.cs
│ ├── SERedisConnectionCache.cs
│ ├── SERedisConnectionDefender.cs
│ ├── SERedisHelper.cs
│ ├── SERedisLock.cs
│ ├── SERedisOperation.cs
│ ├── SERedisOperationForHash.cs
│ ├── SERedisOperationForList.cs
│ ├── SERedisOperationForSet.cs
│ ├── SERedisOperationForSortedSet.cs
│ ├── SERedisOperationForString.cs
│ ├── SERedisOperationForSubPush.cs
│ └── SESentinelClient.cs
├── Data
│ ├── PagedDictionary.cs
│ └── PagedList.cs
├── Extends
│ └── KeyValueConvert.cs
├── Interface
│ ├── IRedisHelper.cs
│ └── IRedisOperation.cs
├── RedisConfig.cs
├── RedisConnectType.cs
├── RedisHelper.cs
├── RedisHelperBuilder.cs
├── RedisLocker.cs
├── Tool
│ └── SerializeHelper.cs
├── Wenli.Drive.Redis.csproj
└── packages.config
└── wenli.drive.redis.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 |
56 | # StyleCop
57 | StyleCopReport.xml
58 |
59 | # Files built by Visual Studio
60 | *_i.c
61 | *_p.c
62 | *_h.h
63 | *.ilk
64 | *.meta
65 | *.obj
66 | *.iobj
67 | *.pch
68 | *.pdb
69 | *.ipdb
70 | *.pgc
71 | *.pgd
72 | *.rsp
73 | *.sbr
74 | *.tlb
75 | *.tli
76 | *.tlh
77 | *.tmp
78 | *.tmp_proj
79 | *.log
80 | *.vspscc
81 | *.vssscc
82 | .builds
83 | *.pidb
84 | *.svclog
85 | *.scc
86 |
87 | # Chutzpah Test files
88 | _Chutzpah*
89 |
90 | # Visual C++ cache files
91 | ipch/
92 | *.aps
93 | *.ncb
94 | *.opendb
95 | *.opensdf
96 | *.sdf
97 | *.cachefile
98 | *.VC.db
99 | *.VC.VC.opendb
100 |
101 | # Visual Studio profiler
102 | *.psess
103 | *.vsp
104 | *.vspx
105 | *.sap
106 |
107 | # Visual Studio Trace Files
108 | *.e2e
109 |
110 | # TFS 2012 Local Workspace
111 | $tf/
112 |
113 | # Guidance Automation Toolkit
114 | *.gpState
115 |
116 | # ReSharper is a .NET coding add-in
117 | _ReSharper*/
118 | *.[Rr]e[Ss]harper
119 | *.DotSettings.user
120 |
121 | # JustCode is a .NET coding add-in
122 | .JustCode
123 |
124 | # TeamCity is a build add-in
125 | _TeamCity*
126 |
127 | # DotCover is a Code Coverage Tool
128 | *.dotCover
129 |
130 | # AxoCover is a Code Coverage Tool
131 | .axoCover/*
132 | !.axoCover/settings.json
133 |
134 | # Visual Studio code coverage results
135 | *.coverage
136 | *.coveragexml
137 |
138 | # NCrunch
139 | _NCrunch_*
140 | .*crunch*.local.xml
141 | nCrunchTemp_*
142 |
143 | # MightyMoose
144 | *.mm.*
145 | AutoTest.Net/
146 |
147 | # Web workbench (sass)
148 | .sass-cache/
149 |
150 | # Installshield output folder
151 | [Ee]xpress/
152 |
153 | # DocProject is a documentation generator add-in
154 | DocProject/buildhelp/
155 | DocProject/Help/*.HxT
156 | DocProject/Help/*.HxC
157 | DocProject/Help/*.hhc
158 | DocProject/Help/*.hhk
159 | DocProject/Help/*.hhp
160 | DocProject/Help/Html2
161 | DocProject/Help/html
162 |
163 | # Click-Once directory
164 | publish/
165 |
166 | # Publish Web Output
167 | *.[Pp]ublish.xml
168 | *.azurePubxml
169 | # Note: Comment the next line if you want to checkin your web deploy settings,
170 | # but database connection strings (with potential passwords) will be unencrypted
171 | *.pubxml
172 | *.publishproj
173 |
174 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
175 | # checkin your Azure Web App publish settings, but sensitive information contained
176 | # in these scripts will be unencrypted
177 | PublishScripts/
178 |
179 | # NuGet Packages
180 | *.nupkg
181 | # The packages folder can be ignored because of Package Restore
182 | **/[Pp]ackages/*
183 | # except build/, which is used as an MSBuild target.
184 | !**/[Pp]ackages/build/
185 | # Uncomment if necessary however generally it will be regenerated when needed
186 | #!**/[Pp]ackages/repositories.config
187 | # NuGet v3's project.json files produces more ignorable files
188 | *.nuget.props
189 | *.nuget.targets
190 |
191 | # Microsoft Azure Build Output
192 | csx/
193 | *.build.csdef
194 |
195 | # Microsoft Azure Emulator
196 | ecf/
197 | rcf/
198 |
199 | # Windows Store app package directories and files
200 | AppPackages/
201 | BundleArtifacts/
202 | Package.StoreAssociation.xml
203 | _pkginfo.txt
204 | *.appx
205 |
206 | # Visual Studio cache files
207 | # files ending in .cache can be ignored
208 | *.[Cc]ache
209 | # but keep track of directories ending in .cache
210 | !*.[Cc]ache/
211 |
212 | # Others
213 | ClientBin/
214 | ~$*
215 | *~
216 | *.dbmdl
217 | *.dbproj.schemaview
218 | *.jfm
219 | *.pfx
220 | *.publishsettings
221 | orleans.codegen.cs
222 |
223 | # Including strong name files can present a security risk
224 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
225 | #*.snk
226 |
227 | # Since there are multiple workflows, uncomment next line to ignore bower_components
228 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
229 | #bower_components/
230 |
231 | # RIA/Silverlight projects
232 | Generated_Code/
233 |
234 | # Backup & report files from converting an old project file
235 | # to a newer Visual Studio version. Backup files are not needed,
236 | # because we have git ;-)
237 | _UpgradeReport_Files/
238 | Backup*/
239 | UpgradeLog*.XML
240 | UpgradeLog*.htm
241 | ServiceFabricBackup/
242 | *.rptproj.bak
243 |
244 | # SQL Server files
245 | *.mdf
246 | *.ldf
247 | *.ndf
248 |
249 | # Business Intelligence projects
250 | *.rdl.data
251 | *.bim.layout
252 | *.bim_*.settings
253 | *.rptproj.rsuser
254 |
255 | # Microsoft Fakes
256 | FakesAssemblies/
257 |
258 | # GhostDoc plugin setting file
259 | *.GhostDoc.xml
260 |
261 | # Node.js Tools for Visual Studio
262 | .ntvs_analysis.dat
263 | node_modules/
264 |
265 | # Visual Studio 6 build log
266 | *.plg
267 |
268 | # Visual Studio 6 workspace options file
269 | *.opt
270 |
271 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
272 | *.vbw
273 |
274 | # Visual Studio LightSwitch build output
275 | **/*.HTMLClient/GeneratedArtifacts
276 | **/*.DesktopClient/GeneratedArtifacts
277 | **/*.DesktopClient/ModelManifest.xml
278 | **/*.Server/GeneratedArtifacts
279 | **/*.Server/ModelManifest.xml
280 | _Pvt_Extensions
281 |
282 | # Paket dependency manager
283 | .paket/paket.exe
284 | paket-files/
285 |
286 | # FAKE - F# Make
287 | .fake/
288 |
289 | # JetBrains Rider
290 | .idea/
291 | *.sln.iml
292 |
293 | # CodeRush
294 | .cr/
295 |
296 | # Python Tools for Visual Studio (PTVS)
297 | __pycache__/
298 | *.pyc
299 |
300 | # Cake - Uncomment if you are using it
301 | # tools/**
302 | # !tools/packages.config
303 |
304 | # Tabs Studio
305 | *.tss
306 |
307 | # Telerik's JustMock configuration file
308 | *.jmconfig
309 |
310 | # BizTalk build output
311 | *.btp.cs
312 | *.btm.cs
313 | *.odx.cs
314 | *.xsd.cs
315 |
316 | # OpenCover UI analysis results
317 | OpenCover/
318 |
319 | # Azure Stream Analytics local run output
320 | ASALocalRun/
321 |
322 | # MSBuild Binary and Structured Log
323 | *.binlog
324 |
325 | # NVidia Nsight GPU debugger configuration file
326 | *.nvuser
327 |
328 | # MFractors (Xamarin productivity tool) working folder
329 | .mfractor/
330 |
331 | # Local History for Visual Studio
332 | .localhistory/
--------------------------------------------------------------------------------
/DriveTest/App.config:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/DriveTest/BatcherTest.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:DriveTest
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:DriveTest
6 | *类 名 称:BatcherTest
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/12/3 17:31:05
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/12/3 17:31:05
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using System;
19 | using Wenli.Drive.Redis;
20 |
21 | namespace DriveTest
22 | {
23 | static class BatcherTest
24 | {
25 | static void Test()
26 | {
27 | Console.WriteLine("Wenli.Drive.Redis 批量操作实例");
28 |
29 | var redisConfig = new RedisConfig()
30 | {
31 | SectionName = "Instance",
32 | Type = RedisConnectType.Instance,
33 | Masters = "127.0.0.1:6379",
34 | Slaves = "127.0.0.1:6380",
35 | Password = "12321",
36 | DefaultDatabase = 0,
37 | BusyRetryWaitMS = 1000
38 | };
39 |
40 | var redisHelper = RedisHelperBuilder.Build(redisConfig);
41 |
42 | using (var redisBatcher = redisHelper.GetRedisOperation().CreateBatcher())
43 | {
44 | for (int i = 0; i < 100; i++)
45 | {
46 | redisBatcher.Batch.StringSetAsync($"batch_{i}", $"val_{i}");
47 | }
48 | }
49 |
50 | Console.Read();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/DriveTest/DemoModel.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2015-2016
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:c91279a5-8753-4ca4-bbdc-d89dfa9dd54d
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:DriveTest
10 | * 命名空间:DriveTest
11 | * 类名称:DemoModel
12 | * 创建时间:2016/12/28 10:20:47
13 | * 创建人:wenli
14 | * 创建说明:
15 | *****************************************************************************************************/
16 | using System;
17 |
18 | namespace DriveTest
19 | {
20 | public class DemoModel
21 | {
22 | public string ID
23 | {
24 | get; set;
25 | }
26 | public string Name
27 | {
28 | get; set;
29 | }
30 | public int Age
31 | {
32 | get; set;
33 | }
34 | public DateTime Created
35 | {
36 | get; set;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/DriveTest/DriveTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {7E8B59D4-683F-4393-864E-C315A79D5A97}
8 | Exe
9 | Properties
10 | DriveTest
11 | DriveTest
12 | v4.6.2
13 | 512
14 | true
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | x64
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 | DriveTest.Program
36 |
37 |
38 |
39 | ..\packages\Microsoft.Bcl.AsyncInterfaces.5.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
40 |
41 |
42 | ..\packages\Microsoft.Extensions.Configuration.Abstractions.5.0.0\lib\net461\Microsoft.Extensions.Configuration.Abstractions.dll
43 |
44 |
45 | ..\packages\Microsoft.Extensions.Configuration.Binder.5.0.0\lib\net461\Microsoft.Extensions.Configuration.Binder.dll
46 |
47 |
48 | ..\packages\Microsoft.Extensions.Primitives.5.0.0\lib\net461\Microsoft.Extensions.Primitives.dll
49 |
50 |
51 | ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
52 |
53 |
54 | ..\packages\Pipelines.Sockets.Unofficial.2.2.0\lib\net461\Pipelines.Sockets.Unofficial.dll
55 |
56 |
57 | ..\packages\StackExchange.Redis.2.2.4\lib\net461\StackExchange.Redis.dll
58 |
59 |
60 |
61 | ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
62 |
63 |
64 |
65 | ..\packages\System.Configuration.ConfigurationManager.5.0.0\lib\net461\System.Configuration.ConfigurationManager.dll
66 |
67 |
68 |
69 |
70 | ..\packages\System.Diagnostics.PerformanceCounter.5.0.0\lib\net461\System.Diagnostics.PerformanceCounter.dll
71 |
72 |
73 |
74 | ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll
75 |
76 |
77 | ..\packages\System.IO.Pipelines.5.0.0\lib\net461\System.IO.Pipelines.dll
78 |
79 |
80 | ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
81 |
82 |
83 |
84 |
85 | ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
86 |
87 |
88 | ..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll
89 |
90 |
91 | ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
92 |
93 |
94 |
95 | ..\packages\System.Security.AccessControl.5.0.0\lib\net461\System.Security.AccessControl.dll
96 |
97 |
98 | ..\packages\System.Security.Permissions.5.0.0\lib\net461\System.Security.Permissions.dll
99 |
100 |
101 | ..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll
102 |
103 |
104 |
105 | ..\packages\System.Threading.Channels.5.0.0\lib\net461\System.Threading.Channels.dll
106 |
107 |
108 | ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
109 |
110 |
111 |
112 | ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | ..\packages\Wenli.Drive.Redis.2.2.8.8\lib\netstandard2.0\Wenli.Drive.Redis.dll
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/DriveTest/Program.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2015-2016
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:c91279a5-8753-4ca4-bbdc-d89dfa9dd54d
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:Program
10 | * 命名空间:DriveTest
11 | * 类名称:DriveTest
12 | * 创建时间:2016/12/28 10:20:47
13 | * 创建人:wenli
14 | * 创建说明:
15 | *****************************************************************************************************/
16 | using System;
17 | using System.Diagnostics;
18 | using System.Threading;
19 | using System.Threading.Tasks;
20 | using Wenli.Drive.Redis;
21 |
22 | namespace DriveTest
23 | {
24 | class Program
25 | {
26 | static void Main(string[] args)
27 | {
28 | Console.Title = "Wenli.Drive.Redis驱动测试";
29 |
30 | Console.WriteLine("Wenli.Drive.Redis test");
31 |
32 | Console.WriteLine("输入s 测试哨兵模式,输入c测试cluster模式,M为连续,l为锁测试,其它为单实例模式");
33 |
34 |
35 | var redisConfig = new RedisConfig()
36 | {
37 | SectionName = "Instance",
38 | Type = RedisConnectType.Instance,
39 | Masters = "127.0.0.1:6379",
40 | Slaves = "127.0.0.1:6380",
41 | Password = "12321",
42 | DefaultDatabase = 0,
43 | BusyRetryWaitMS = 1000
44 | };
45 |
46 |
47 | var sentinelConfig = new RedisConfig()
48 | {
49 | SectionName = "Sentinel",
50 | Type = RedisConnectType.Sentinel,
51 | Masters = "127.0.0.1:26379",
52 | Password = "12321",
53 | ServiceName = "mymaster"
54 | };
55 |
56 | var clusterConfig = new RedisConfig()
57 | {
58 | SectionName= "Cluster",
59 | Type = RedisConnectType.Cluster,
60 | Masters = "127.0.0.1:6380",
61 | Password = "12321"
62 | };
63 |
64 | while (true)
65 | {
66 |
67 | var c = Console.ReadLine();
68 |
69 | if (c.ToUpper() == "S")
70 | {
71 | #region sentinel
72 | Console.WriteLine("Wenli.Drive.Redis test 进入哨兵模式---------------------");
73 |
74 | var redisHelper = RedisHelperBuilder.Build(clusterConfig);
75 |
76 |
77 | #region string
78 | Console.ReadLine();
79 | Console.WriteLine("string get/set test");
80 |
81 | redisHelper.GetRedisOperation().StringSet("abcabcabc", "123123");
82 | Console.WriteLine("写入key:abcabcabc,value:123123");
83 |
84 | var str = redisHelper.GetRedisOperation().StringGet("abcabcabc");
85 | Console.WriteLine("查询key:abcabcabc,value:" + str);
86 |
87 | redisHelper.GetRedisOperation().KeyDelete("abcabcabc");
88 | Console.WriteLine("移除key:abcabcabc");
89 | #endregion
90 |
91 | #region hashset
92 | Console.ReadLine();
93 | Console.WriteLine("hashset get/set test");
94 | var testModel = new DemoModel()
95 | {
96 | ID = Guid.NewGuid().ToString("N"),
97 | Age = 18,
98 | Name = "Kitty",
99 | Created = DateTime.Now
100 | };
101 |
102 | redisHelper.GetRedisOperation().HashSet(testModel.Name, testModel.ID, testModel);
103 | Console.WriteLine(string.Format("写入hashid:{0},key:{1}", testModel.Name, testModel.ID));
104 |
105 | testModel = redisHelper.GetRedisOperation().HashGet(testModel.Name, testModel.ID);
106 | Console.WriteLine(string.Format("查询hashid:{0},key:{1}", testModel.Name, testModel.ID));
107 |
108 | redisHelper.GetRedisOperation().HashDelete(testModel.Name, testModel.ID);
109 | Console.WriteLine("移除hash");
110 | #endregion
111 |
112 | #region 队列
113 | Console.ReadLine();
114 | Console.WriteLine("list test");
115 |
116 | redisHelper.GetRedisOperation().Enqueue("list", "listvalue");
117 | Console.WriteLine("入队:list,value:listvalue");
118 |
119 | Console.WriteLine("list.coumt:" + redisHelper.GetRedisOperation().QueueCount("list"));
120 |
121 | Console.WriteLine(string.Format("出队:list,value:{0}", redisHelper.GetRedisOperation().Dnqueue("list")));
122 | Console.WriteLine("list.coumt:" + redisHelper.GetRedisOperation().QueueCount("list"));
123 | #endregion
124 |
125 | #region sortedset
126 | Console.ReadLine();
127 | Console.WriteLine("sortedset test");
128 | Console.WriteLine(string.Format("sortedset add :{0}", redisHelper.GetRedisOperation().SortedSetAdd("sortedset", "sortedset", 0)));
129 | var list = redisHelper.GetRedisOperation().GetSortedSetRangeByRankWithSocres("sortedset", 0, 10000, 1, 9999, true);
130 | Console.WriteLine(string.Format("sortedset getlist :{0}", list));
131 | Console.WriteLine(string.Format("sortedset remove :{0}", redisHelper.GetRedisOperation().RemoveItemFromSortedSet("sortedset", "sortedset")));
132 | #endregion
133 |
134 | #region pub/sub
135 | Console.ReadLine();
136 | Console.WriteLine("sub/pub test");
137 |
138 | Console.WriteLine("订阅频道:happy");
139 |
140 | redisHelper.GetRedisOperation().SubscribeWithChannel("happy", (x, y) =>
141 | {
142 | Console.WriteLine(string.Format("订阅者收到消息;频道:{0},消息:{1}", x, y));
143 | });
144 |
145 | Console.WriteLine("发布频道happy 10 条测试消息");
146 | for (int i = 1; i <= 10; i++)
147 | {
148 | redisHelper.GetRedisOperation().Publish("happy", "this is a test message" + i);
149 | Thread.Sleep(400);
150 | }
151 | #endregion
152 | Console.ReadLine();
153 | redisHelper.GetRedisOperation().Unsubscribe("happy");
154 |
155 |
156 | #endregion
157 | }
158 | else if (c.ToUpper() == "C")
159 | {
160 | #region cluster
161 | Console.WriteLine("Wenli.Drive.Redis test 进入集群模式---------------------");
162 |
163 | var redisHelper = RedisHelperBuilder.Build(clusterConfig);
164 |
165 | #region string
166 | Console.ReadLine();
167 | Console.WriteLine("string get/set test");
168 |
169 | redisHelper.GetRedisOperation().StringSet("abcabcabc", "123123");
170 | Console.WriteLine("写入key:abcabcabc,value:123123");
171 |
172 | var str = redisHelper.GetRedisOperation().StringGet("abcabcabc");
173 | Console.WriteLine("查询key:abcabcabc,value:" + str);
174 |
175 | redisHelper.GetRedisOperation().KeyDelete("abcabcabc");
176 | Console.WriteLine("移除key:abcabcabc");
177 | #endregion
178 |
179 | #region hashset
180 | Console.ReadLine();
181 | Console.WriteLine("hashset get/set test");
182 | var testModel = new DemoModel()
183 | {
184 | ID = Guid.NewGuid().ToString("N"),
185 | Age = 18,
186 | Name = "Kitty",
187 | Created = DateTime.Now
188 | };
189 |
190 | redisHelper.GetRedisOperation().HashSet(testModel.Name, testModel.ID, testModel);
191 | Console.WriteLine(string.Format("写入hashid:{0},key:{1}", testModel.Name, testModel.ID));
192 |
193 | testModel = redisHelper.GetRedisOperation().HashGet(testModel.Name, testModel.ID);
194 | Console.WriteLine(string.Format("查询hashid:{0},key:{1}", testModel.Name, testModel.ID));
195 |
196 | redisHelper.GetRedisOperation().HashDelete(testModel.Name, testModel.ID);
197 | Console.WriteLine("移除hash");
198 | #endregion
199 |
200 | #region 队列
201 | Console.ReadLine();
202 | Console.WriteLine("list test");
203 |
204 | redisHelper.GetRedisOperation().Enqueue("list", "listvalue");
205 | Console.WriteLine("入队:list,value:listvalue");
206 |
207 | Console.WriteLine("list.coumt:" + redisHelper.GetRedisOperation().QueueCount("list"));
208 |
209 | Console.WriteLine(string.Format("出队:list,value:{0}", redisHelper.GetRedisOperation().Dnqueue("list")));
210 | Console.WriteLine("list.coumt:" + redisHelper.GetRedisOperation().QueueCount("list"));
211 | #endregion
212 |
213 |
214 | #region pub/sub
215 | Console.ReadLine();
216 | Console.WriteLine("sub/pub test");
217 |
218 | Console.WriteLine("订阅频道:happy");
219 |
220 | redisHelper.GetRedisOperation().SubscribeWithChannel("happy", (x, y) =>
221 | {
222 | Console.WriteLine(string.Format("订阅者收到消息;频道:{0},消息:{1}", x, y));
223 | });
224 |
225 | Console.WriteLine("发布频道happy 10 条测试消息");
226 | for (int i = 1; i <= 10; i++)
227 | {
228 | redisHelper.GetRedisOperation().Publish("happy", "this is a test message" + i);
229 | Thread.Sleep(400);
230 | }
231 | #endregion
232 |
233 | Console.ReadLine();
234 |
235 | redisHelper.GetRedisOperation().Unsubscribe("happy");
236 | #endregion
237 | }
238 | else if (c.ToUpper() == "M")
239 | {
240 | #region default redis
241 | Console.WriteLine("Wenli.Drive.Redis test 进入连续测试模式---------------------");
242 |
243 | string value = "123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式123123进入连续测试模式";
244 |
245 | var td1 = new Thread(new ThreadStart(() =>
246 | {
247 | var redisHelper = RedisHelperBuilder.Build(sentinelConfig);
248 |
249 | Parallel.For(0, 100000, countIndex =>
250 | {
251 | #region string
252 | Console.WriteLine("string get/set test");
253 | redisHelper.GetRedisOperation().StringSet(countIndex.ToString(), value);
254 | Console.WriteLine("写入key:abcabcabc,value:123123");
255 |
256 | var str = redisHelper.GetRedisOperation().StringGet(countIndex.ToString());
257 | Console.WriteLine("查询key:abcabcabc,value:" + str);
258 |
259 | redisHelper.GetRedisOperation().KeyDelete(countIndex.ToString());
260 | Console.WriteLine("移除key:abcabcabc");
261 | #endregion
262 |
263 | #region hashset
264 | Console.WriteLine("hashset get/set test");
265 | var testModel = new DemoModel()
266 | {
267 | ID = Guid.NewGuid().ToString("N"),
268 | Age = 18,
269 | Name = "Kitty",
270 | Created = DateTime.Now
271 | };
272 |
273 | redisHelper.GetRedisOperation().HashSet(testModel.Name, testModel.ID, testModel);
274 | Console.WriteLine(string.Format("写入hashid:{0},key:{1}", testModel.Name, testModel.ID));
275 |
276 | testModel = redisHelper.GetRedisOperation().HashGet(testModel.Name, testModel.ID);
277 | Console.WriteLine(string.Format("查询hashid:{0},key:{1}", testModel.Name, testModel.ID));
278 |
279 | redisHelper.GetRedisOperation().HashDelete(testModel.Name, testModel.ID);
280 | Console.WriteLine("移除hash");
281 | #endregion
282 |
283 | });
284 |
285 | }));
286 | var td2 = new Thread(new ThreadStart(() =>
287 | {
288 | Parallel.For(0, 100000, countIndex =>
289 | {
290 | var redisHelper = RedisHelperBuilder.Build(sentinelConfig);
291 |
292 | #region string
293 | Console.WriteLine("string get/set test");
294 | redisHelper.GetRedisOperation().StringSet(countIndex.ToString(), value);
295 | Console.WriteLine("写入key:abcabcabc,value:123123");
296 |
297 | var str = redisHelper.GetRedisOperation().StringGet(countIndex.ToString());
298 | Console.WriteLine("查询key:abcabcabc,value:" + str);
299 |
300 | redisHelper.GetRedisOperation().KeyDelete(countIndex.ToString());
301 | Console.WriteLine("移除key:abcabcabc");
302 | #endregion
303 |
304 | #region hashset
305 | Console.WriteLine("hashset get/set test");
306 | var testModel = new DemoModel()
307 | {
308 | ID = Guid.NewGuid().ToString("N"),
309 | Age = 18,
310 | Name = "Kitty",
311 | Created = DateTime.Now
312 | };
313 |
314 | redisHelper.GetRedisOperation().HashSet(testModel.Name, testModel.ID, testModel);
315 | Console.WriteLine(string.Format("写入hashid:{0},key:{1}", testModel.Name, testModel.ID));
316 |
317 | testModel = redisHelper.GetRedisOperation().HashGet(testModel.Name, testModel.ID);
318 | Console.WriteLine(string.Format("查询hashid:{0},key:{1}", testModel.Name, testModel.ID));
319 |
320 | redisHelper.GetRedisOperation().HashDelete(testModel.Name, testModel.ID);
321 | Console.WriteLine("移除hash");
322 | #endregion
323 |
324 | });
325 | }));
326 |
327 | td1.Start();
328 | td2.Start();
329 |
330 | while (td1.IsAlive || td2.IsAlive)
331 | {
332 | Thread.Sleep(50);
333 | }
334 |
335 | Console.WriteLine("Wenli.Drive.Redis test 任务已完成!---------------------");
336 | #endregion
337 | }
338 | else if (c.ToLower() == "l")
339 | {
340 | var redisHelper = RedisHelperBuilder.Build(redisConfig);
341 |
342 | Stopwatch sw = new Stopwatch();
343 |
344 | string key = "lock_test";
345 |
346 | int total = 100000;
347 |
348 | sw.Start();
349 |
350 | Parallel.For(0, 100000, i =>
351 | {
352 | total--;
353 | });
354 |
355 | Console.WriteLine(string.Format("未加锁 total:{0} time:{1}", total, sw.ElapsedMilliseconds));
356 | sw.Reset();
357 | Console.WriteLine("回车锁测试");
358 | Console.ReadLine();
359 | sw.Restart();
360 |
361 | total = 100000;
362 |
363 | int f = 0;
364 |
365 | int val = 1;
366 |
367 | Parallel.For(0, total, i =>
368 | {
369 | Stopwatch sw1 = new Stopwatch();
370 |
371 | sw1.Start();
372 |
373 | if (redisHelper.GetRedisOperation().Lock(key, 30000, 10))
374 | {
375 |
376 | if (!int.TryParse(redisHelper.GetRedisOperation().StringGet(key), out val))
377 | {
378 | val = 1;
379 | }
380 | else
381 | {
382 | val++;
383 | }
384 |
385 | redisHelper.GetRedisOperation().StringSet(key, val.ToString());
386 |
387 | redisHelper.GetRedisOperation().UnLock(key);
388 | }
389 | else
390 | {
391 | Interlocked.Add(ref f, 1);
392 | Console.Write("f:{0}", f);
393 | }
394 |
395 | sw1.Stop();
396 | });
397 |
398 | Console.WriteLine(string.Format("已加锁 total:{0} time:{1} f:{2} StringGet:{3}", total, sw.ElapsedMilliseconds, f, redisHelper.GetRedisOperation().StringGet(key)));
399 | sw.Reset();
400 | Console.ReadLine();
401 | redisHelper.GetRedisOperation().KeyDelete(key);
402 |
403 |
404 |
405 | }
406 | else
407 | {
408 | #region default redis
409 | Console.WriteLine("Wenli.Drive.Redis test 进入单实例模式---------------------");
410 |
411 | var redisHelper = RedisHelperBuilder.Build(redisConfig);
412 |
413 | #region string
414 | Console.ReadLine();
415 | Console.WriteLine("string get/set test");
416 |
417 | redisHelper.GetRedisOperation(12).StringSet("abcabcabc", "123123");
418 | Console.WriteLine("写入key:abcabcabc,value:123123");
419 |
420 | var str = redisHelper.GetRedisOperation(12).StringGet("abcabcabc");
421 | Console.WriteLine("查询key:abcabcabc,value:" + str);
422 |
423 | redisHelper.GetRedisOperation(12).KeyDelete("abcabcabc");
424 | Console.WriteLine("移除key:abcabcabc");
425 | #endregion
426 |
427 | #region hashset
428 | Console.ReadLine();
429 | Console.WriteLine("hashset get/set test");
430 | var testModel = new DemoModel()
431 | {
432 | ID = Guid.NewGuid().ToString("N"),
433 | Age = 18,
434 | Name = "Kitty",
435 | Created = DateTime.Now
436 | };
437 |
438 | redisHelper.GetRedisOperation().HashSet(testModel.Name, testModel.ID, testModel);
439 | Console.WriteLine(string.Format("写入hashid:{0},key:{1}", testModel.Name, testModel.ID));
440 |
441 | testModel = redisHelper.GetRedisOperation().HashGet(testModel.Name, testModel.ID);
442 | Console.WriteLine(string.Format("查询hashid:{0},key:{1}", testModel.Name, testModel.ID));
443 |
444 | redisHelper.GetRedisOperation().HashGetAll(testModel.Name, 1, 1);
445 |
446 | redisHelper.GetRedisOperation().HashDelete(testModel.Name, testModel.ID);
447 | Console.WriteLine("移除hash");
448 | #endregion
449 |
450 | #region 队列
451 | Console.ReadLine();
452 | Console.WriteLine("list test");
453 |
454 | redisHelper.GetRedisOperation().Enqueue("list", "listvalue");
455 | Console.WriteLine("入队:list,value:listvalue");
456 |
457 | Console.WriteLine("list.coumt:" + redisHelper.GetRedisOperation().QueueCount("list"));
458 |
459 | Console.WriteLine(string.Format("出队:list,value:{0}", redisHelper.GetRedisOperation().Dnqueue("list")));
460 | Console.WriteLine("list.coumt:" + redisHelper.GetRedisOperation().QueueCount("list"));
461 | #endregion
462 |
463 | #region pub/sub
464 | Console.ReadLine();
465 | Console.WriteLine("sub/pub test");
466 |
467 | Console.WriteLine("订阅频道:happy");
468 |
469 | redisHelper.GetRedisOperation().SubscribeWithChannel("happy", (x, y) =>
470 | {
471 | Console.WriteLine(string.Format("订阅者收到消息;频道:{0},消息:{1}", x, y));
472 | });
473 |
474 | Console.WriteLine("发布频道happy 10 条测试消息");
475 | for (int i = 1; i <= 10; i++)
476 | {
477 | redisHelper.GetRedisOperation().Publish("happy", "this is a test message" + i);
478 | Thread.Sleep(400);
479 | }
480 | #endregion
481 |
482 | Console.ReadLine();
483 |
484 | redisHelper.GetRedisOperation().Unsubscribe("happy");
485 |
486 | #endregion
487 | }
488 | }
489 |
490 | Console.ReadLine();
491 | }
492 | }
493 | }
494 |
--------------------------------------------------------------------------------
/DriveTest/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("DriveTest")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("DriveTest")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("7e8b59d4-683f-4393-864e-c315a79d5a97")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
33 | //通过使用 "*",如下所示:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/DriveTest/packages.config:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/RedisDrive.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.902
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wenli.Drive.Redis", "Wenli.Drive.Redis\Wenli.Drive.Redis.csproj", "{224E5838-57C6-41E8-B2DE-AF1BEF7F6EC5}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DriveTest", "DriveTest\DriveTest.csproj", "{7E8B59D4-683F-4393-864E-C315A79D5A97}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {224E5838-57C6-41E8-B2DE-AF1BEF7F6EC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {224E5838-57C6-41E8-B2DE-AF1BEF7F6EC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {224E5838-57C6-41E8-B2DE-AF1BEF7F6EC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {224E5838-57C6-41E8-B2DE-AF1BEF7F6EC5}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {7E8B59D4-683F-4393-864E-C315A79D5A97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {7E8B59D4-683F-4393-864E-C315A79D5A97}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {7E8B59D4-683F-4393-864E-C315A79D5A97}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {7E8B59D4-683F-4393-864E-C315A79D5A97}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {D2EC9F5B-3DB0-4E76-BD68-3CF8A589D914}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/VisualStudio.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 |
33 | # Visual Studio 2015/2017 cache/options directory
34 | .vs/
35 | # Uncomment if you have tasks that create the project's static files in wwwroot
36 | #wwwroot/
37 |
38 | # Visual Studio 2017 auto generated files
39 | Generated\ Files/
40 |
41 | # MSTest test Results
42 | [Tt]est[Rr]esult*/
43 | [Bb]uild[Ll]og.*
44 |
45 | # NUnit
46 | *.VisualState.xml
47 | TestResult.xml
48 | nunit-*.xml
49 |
50 | # Build Results of an ATL Project
51 | [Dd]ebugPS/
52 | [Rr]eleasePS/
53 | dlldata.c
54 |
55 | # Benchmark Results
56 | BenchmarkDotNet.Artifacts/
57 |
58 | # .NET Core
59 | project.lock.json
60 | project.fragment.lock.json
61 | artifacts/
62 |
63 | # StyleCop
64 | StyleCopReport.xml
65 |
66 | # Files built by Visual Studio
67 | *_i.c
68 | *_p.c
69 | *_h.h
70 | *.ilk
71 | *.meta
72 | *.obj
73 | *.iobj
74 | *.pch
75 | *.pdb
76 | *.ipdb
77 | *.pgc
78 | *.pgd
79 | *.rsp
80 | *.sbr
81 | *.tlb
82 | *.tli
83 | *.tlh
84 | *.tmp
85 | *.tmp_proj
86 | *_wpftmp.csproj
87 | *.log
88 | *.vspscc
89 | *.vssscc
90 | .builds
91 | *.pidb
92 | *.svclog
93 | *.scc
94 |
95 | # Chutzpah Test files
96 | _Chutzpah*
97 |
98 | # Visual C++ cache files
99 | ipch/
100 | *.aps
101 | *.ncb
102 | *.opendb
103 | *.opensdf
104 | *.sdf
105 | *.cachefile
106 | *.VC.db
107 | *.VC.VC.opendb
108 |
109 | # Visual Studio profiler
110 | *.psess
111 | *.vsp
112 | *.vspx
113 | *.sap
114 |
115 | # Visual Studio Trace Files
116 | *.e2e
117 |
118 | # TFS 2012 Local Workspace
119 | $tf/
120 |
121 | # Guidance Automation Toolkit
122 | *.gpState
123 |
124 | # ReSharper is a .NET coding add-in
125 | _ReSharper*/
126 | *.[Rr]e[Ss]harper
127 | *.DotSettings.user
128 |
129 | # JustCode is a .NET coding add-in
130 | .JustCode
131 |
132 | # TeamCity is a build add-in
133 | _TeamCity*
134 |
135 | # DotCover is a Code Coverage Tool
136 | *.dotCover
137 |
138 | # AxoCover is a Code Coverage Tool
139 | .axoCover/*
140 | !.axoCover/settings.json
141 |
142 | # Visual Studio code coverage results
143 | *.coverage
144 | *.coveragexml
145 |
146 | # NCrunch
147 | _NCrunch_*
148 | .*crunch*.local.xml
149 | nCrunchTemp_*
150 |
151 | # MightyMoose
152 | *.mm.*
153 | AutoTest.Net/
154 |
155 | # Web workbench (sass)
156 | .sass-cache/
157 |
158 | # Installshield output folder
159 | [Ee]xpress/
160 |
161 | # DocProject is a documentation generator add-in
162 | DocProject/buildhelp/
163 | DocProject/Help/*.HxT
164 | DocProject/Help/*.HxC
165 | DocProject/Help/*.hhc
166 | DocProject/Help/*.hhk
167 | DocProject/Help/*.hhp
168 | DocProject/Help/Html2
169 | DocProject/Help/html
170 |
171 | # Click-Once directory
172 | publish/
173 |
174 | # Publish Web Output
175 | *.[Pp]ublish.xml
176 | *.azurePubxml
177 | # Note: Comment the next line if you want to checkin your web deploy settings,
178 | # but database connection strings (with potential passwords) will be unencrypted
179 | *.pubxml
180 | *.publishproj
181 |
182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
183 | # checkin your Azure Web App publish settings, but sensitive information contained
184 | # in these scripts will be unencrypted
185 | PublishScripts/
186 |
187 | # NuGet Packages
188 | *.nupkg
189 | # NuGet Symbol Packages
190 | *.snupkg
191 | # The packages folder can be ignored because of Package Restore
192 | **/[Pp]ackages/*
193 | # except build/, which is used as an MSBuild target.
194 | !**/[Pp]ackages/build/
195 | # Uncomment if necessary however generally it will be regenerated when needed
196 | #!**/[Pp]ackages/repositories.config
197 | # NuGet v3's project.json files produces more ignorable files
198 | *.nuget.props
199 | *.nuget.targets
200 |
201 | # Microsoft Azure Build Output
202 | csx/
203 | *.build.csdef
204 |
205 | # Microsoft Azure Emulator
206 | ecf/
207 | rcf/
208 |
209 | # Windows Store app package directories and files
210 | AppPackages/
211 | BundleArtifacts/
212 | Package.StoreAssociation.xml
213 | _pkginfo.txt
214 | *.appx
215 | *.appxbundle
216 | *.appxupload
217 |
218 | # Visual Studio cache files
219 | # files ending in .cache can be ignored
220 | *.[Cc]ache
221 | # but keep track of directories ending in .cache
222 | !?*.[Cc]ache/
223 |
224 | # Others
225 | ClientBin/
226 | ~$*
227 | *~
228 | *.dbmdl
229 | *.dbproj.schemaview
230 | *.jfm
231 | *.pfx
232 | *.publishsettings
233 | orleans.codegen.cs
234 |
235 | # Including strong name files can present a security risk
236 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
237 | #*.snk
238 |
239 | # Since there are multiple workflows, uncomment next line to ignore bower_components
240 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
241 | #bower_components/
242 |
243 | # RIA/Silverlight projects
244 | Generated_Code/
245 |
246 | # Backup & report files from converting an old project file
247 | # to a newer Visual Studio version. Backup files are not needed,
248 | # because we have git ;-)
249 | _UpgradeReport_Files/
250 | Backup*/
251 | UpgradeLog*.XML
252 | UpgradeLog*.htm
253 | ServiceFabricBackup/
254 | *.rptproj.bak
255 |
256 | # SQL Server files
257 | *.mdf
258 | *.ldf
259 | *.ndf
260 |
261 | # Business Intelligence projects
262 | *.rdl.data
263 | *.bim.layout
264 | *.bim_*.settings
265 | *.rptproj.rsuser
266 | *- [Bb]ackup.rdl
267 | *- [Bb]ackup ([0-9]).rdl
268 | *- [Bb]ackup ([0-9][0-9]).rdl
269 |
270 | # Microsoft Fakes
271 | FakesAssemblies/
272 |
273 | # GhostDoc plugin setting file
274 | *.GhostDoc.xml
275 |
276 | # Node.js Tools for Visual Studio
277 | .ntvs_analysis.dat
278 | node_modules/
279 |
280 | # Visual Studio 6 build log
281 | *.plg
282 |
283 | # Visual Studio 6 workspace options file
284 | *.opt
285 |
286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
287 | *.vbw
288 |
289 | # Visual Studio LightSwitch build output
290 | **/*.HTMLClient/GeneratedArtifacts
291 | **/*.DesktopClient/GeneratedArtifacts
292 | **/*.DesktopClient/ModelManifest.xml
293 | **/*.Server/GeneratedArtifacts
294 | **/*.Server/ModelManifest.xml
295 | _Pvt_Extensions
296 |
297 | # Paket dependency manager
298 | .paket/paket.exe
299 | paket-files/
300 |
301 | # FAKE - F# Make
302 | .fake/
303 |
304 | # CodeRush personal settings
305 | .cr/personal
306 |
307 | # Python Tools for Visual Studio (PTVS)
308 | __pycache__/
309 | *.pyc
310 |
311 | # Cake - Uncomment if you are using it
312 | # tools/**
313 | # !tools/packages.config
314 |
315 | # Tabs Studio
316 | *.tss
317 |
318 | # Telerik's JustMock configuration file
319 | *.jmconfig
320 |
321 | # BizTalk build output
322 | *.btp.cs
323 | *.btm.cs
324 | *.odx.cs
325 | *.xsd.cs
326 |
327 | # OpenCover UI analysis results
328 | OpenCover/
329 |
330 | # Azure Stream Analytics local run output
331 | ASALocalRun/
332 |
333 | # MSBuild Binary and Structured Log
334 | *.binlog
335 |
336 | # NVidia Nsight GPU debugger configuration file
337 | *.nvuser
338 |
339 | # MFractors (Xamarin productivity tool) working folder
340 | .mfractor/
341 |
342 | # Local History for Visual Studio
343 | .localhistory/
344 |
345 | # BeatPulse healthcheck temp database
346 | healthchecksdb
347 |
348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
349 | MigrationBackup/
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/App.config:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/RedisBatcher.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Im.Data.Redis.Core
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Im.Data.Redis.Core
6 | *类 名 称:RedisBatcher
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/9/17 14:42:04
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/9/17 14:42:04
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using StackExchange.Redis;
19 | using System;
20 |
21 | namespace Wenli.Drive.Redis
22 | {
23 | ///
24 | /// RedisBatcher
25 | ///
26 | public class RedisBatcher : IDisposable
27 | {
28 | IBatch _batch;
29 |
30 | ///
31 | /// RedisBatcher
32 | ///
33 | ///
34 | internal RedisBatcher(IDatabase dataBase)
35 | {
36 | _batch = dataBase.CreateBatch();
37 | }
38 |
39 | ///
40 | /// 批量
41 | ///
42 | public IBatch Batch
43 | {
44 | get => _batch;
45 | }
46 |
47 | ///
48 | /// Execute
49 | ///
50 | public void Execute()
51 | {
52 | _batch.Execute();
53 | }
54 |
55 | ///
56 | /// Dispose
57 | ///
58 | public void Dispose()
59 | {
60 | Execute();
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/RedisConnection.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Im.Data.Redis.Core
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis
6 | *类 名 称:RedisConnection
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/7/6 16:07:59
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/7/6 16:07:59
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using StackExchange.Redis;
19 |
20 | namespace Wenli.Drive.Redis
21 | {
22 | ///
23 | /// 自定义RedisConnection
24 | ///
25 | public class RedisConnection
26 | {
27 | ///
28 | /// ConnectionMultiplexer
29 | ///
30 | public ConnectionMultiplexer Connection { get; set; }
31 |
32 | ///
33 | /// 修复中
34 | ///
35 | public bool Repairing { get; set; } = false;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisConnection.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2015-2016
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:29c08bfd-59ed-42b7-b2f9-b344225840a3
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:$projectname$
10 | * 命名空间:Wenli.Drive.Redis.Core
11 | * 类名称:SERedisConnection
12 | * 创建时间:2016/11/8 20:31:02
13 | * 创建人:wenli
14 | * 创建说明:
15 | *****************************************************************************************************/
16 |
17 | using StackExchange.Redis;
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using Wenli.Drive.Redis.Extends;
22 |
23 | namespace Wenli.Drive.Redis.Core
24 | {
25 | ///
26 | /// redis 连接
27 | ///
28 | public class SERedisConnection
29 | {
30 | private readonly int _dbIndex;
31 |
32 | private readonly string _sectionName;
33 |
34 | ///
35 | /// RedisConnection
36 | ///
37 | public RedisConnection RedisConnection { get; private set; }
38 |
39 | ///
40 | /// 连接字符串
41 | ///
42 | public string Configuration { get; set; }
43 |
44 | ///
45 | /// redis 连接
46 | ///
47 | ///
48 | ///
49 | public SERedisConnection(string sectionName, int dbIndex)
50 | {
51 | _sectionName = sectionName;
52 | _dbIndex = dbIndex;
53 | RedisConnection = SERedisConnectionCache.Get(_sectionName);
54 | if (RedisConnection == null || RedisConnection.Connection == null || !RedisConnection.Connection.IsConnected || RedisConnection.Repairing) throw new Exception("Redis 连接未初始化或正在修复中,无法执行此操作,sectionName:" + sectionName);
55 | Configuration = RedisConnection.Connection.Configuration;
56 | }
57 |
58 | ///
59 | /// 获取db
60 | ///
61 | ///
62 | public IDatabase GetDatabase()
63 | {
64 | return RedisConnection.Connection.GetDatabase(_dbIndex);
65 | }
66 |
67 | ///
68 | /// 创建批量处理
69 | ///
70 | ///
71 | public RedisBatcher CreateBatcher()
72 | {
73 | return new RedisBatcher(RedisConnection.Connection.GetDatabase(_dbIndex));
74 | }
75 |
76 | ///
77 | /// 获取订阅
78 | ///
79 | ///
80 | public ISubscriber GetSubscriber()
81 | {
82 | return RedisConnection.Connection.GetSubscriber();
83 | }
84 |
85 | ///
86 | /// 尝试修复连接
87 | ///
88 | internal void TryRepairConnection()
89 | {
90 | RedisConnection.Repairing = true;
91 |
92 | RedisConnection = new SERedisConnectionDefender(_sectionName, Configuration).FreeAndConnect(RedisConnection);
93 |
94 | RedisConnection.Repairing = false;
95 | }
96 |
97 | ///
98 | /// 获取某服务器上全部keys
99 | ///
100 | ///
101 | ///
102 | [Obsolete("此方法只用于兼容老数据,且本方法只能查询db0,建议使用sortedset来保存keys")]
103 | public List Keys(string patten = "*")
104 | {
105 | var firstConfigEndPoint = RedisConnection.Connection.GetEndPoints()[0];
106 | var anyServer = RedisConnection.Connection.GetServer(firstConfigEndPoint);
107 |
108 | var lastResult = new List();
109 | if (anyServer.ServerType == ServerType.Cluster)
110 | {
111 | // 这个操作比较费时, 使用从来处理
112 | var allMasterNodes = anyServer.ClusterConfiguration.Nodes.Where(n => !n.IsSlave);
113 |
114 | foreach (var masterNode in allMasterNodes)
115 | {
116 | var runCommandServer = masterNode;
117 | if (masterNode.Children.Count > 0)
118 | {
119 | runCommandServer = masterNode.Children.First();
120 | }
121 | var resultsInOneServer = RedisConnection.Connection.GetServer(runCommandServer.EndPoint).Keys(pattern: patten).Select(b => b.ToString()).ToList();
122 | lastResult.AddRange(resultsInOneServer);
123 | }
124 |
125 | return lastResult;
126 | }
127 | else
128 | {
129 | return anyServer.Keys(pattern: patten).Select(b => b.ToString()).ToList();
130 | }
131 | }
132 |
133 | ///
134 | /// 获取某服务器上全部keys(此方法目前只支持cluster模式)
135 | ///
136 | ///
137 | ///
138 | ///
139 | ///
140 | public void Keys(Action> callback, string patten = "*", int size = 10000)
141 | {
142 | if (callback == null) return;
143 | var firstConfigEndPoint = RedisConnection.Connection.GetEndPoints()[0];
144 | var anyServer = RedisConnection.Connection.GetServer(firstConfigEndPoint);
145 |
146 | if (anyServer.ServerType == ServerType.Cluster)
147 | {
148 | // 这个操作比较费时, 使用从来处理
149 | var allMasterNodes = anyServer.ClusterConfiguration.Nodes.Where(n => !n.IsSlave);
150 |
151 | foreach (var masterNode in allMasterNodes)
152 | {
153 | var runCommandServer = masterNode;
154 | //LogCom.WriteInfoLog($"master node :NodeId [{masterNode.NodeId}] : EndPoint [{masterNode.EndPoint.ToString()}] : ChildrenCount[{masterNode.Children.Count}]");
155 |
156 | // 驱动自带的 preferslave 不管用,还是运行在了master上,所以自己手动获取slave
157 | var allAliveSlaves = masterNode.Children.Where(r => r.IsConnected).ToList();
158 | if (allAliveSlaves.Count > 0)
159 | {
160 | runCommandServer = allAliveSlaves.First();
161 | }
162 | //LogCom.WriteInfoLog($"run keys command on Server :NodeId [{runCommandServer.NodeId}] : EndPoint[{runCommandServer.EndPoint.ToString()}]");
163 |
164 | var resultsInOneServer = RedisConnection.Connection.GetServer(runCommandServer.EndPoint).Keys(pattern: patten, pageSize: size).Select(b => b.ToString()).ToList();
165 | callback(resultsInOneServer);
166 | }
167 | }
168 | else
169 | {
170 | callback(anyServer.Keys(pattern: patten, pageSize: size).Select(b => b.ToString()).ToList());
171 | //yield return anyServer.Keys(pattern: patten).Select(b => b.ToString()).ToList();
172 | }
173 | }
174 |
175 | ///
176 | /// 获取指定keys
177 | ///
178 | ///
179 | ///
180 | ///
181 | ///
182 | [Obsolete("此方法只用于兼容老数据,且本方法只能查询db0,建议使用sortedset来保存keys")]
183 | public List Keys(int dbIndex = -1, string patten = "*", int count = 20)
184 | {
185 | var result = new List();
186 |
187 | var endpoint = RedisConnection.Connection.GetEndPoints()[0];
188 |
189 | var rs = RedisConnection.Connection.GetServer(endpoint);
190 |
191 | var data = rs.Keys(dbIndex, patten, count, CommandFlags.PreferSlave);
192 |
193 | if (data != null && data.Any())
194 | {
195 | result.AddRange(data.ToList().ConvertTo());
196 | }
197 |
198 | return result = result.Take(count).ToList();
199 | }
200 |
201 |
202 | }
203 | }
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisConnectionCache.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis.Core
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis.Core
6 | *类 名 称:SERedisConnectionCache
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/6/30 9:53:34
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/6/30 9:53:34
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using StackExchange.Redis;
19 | using System.Collections.Concurrent;
20 |
21 | namespace Wenli.Drive.Redis.Core
22 | {
23 | ///
24 | /// SERedisConnectionCache
25 | ///
26 | internal static class SERedisConnectionCache
27 | {
28 | static ConcurrentDictionary _cache = null;
29 |
30 |
31 | ///
32 | /// SERedisConnectionCache
33 | ///
34 | static SERedisConnectionCache()
35 | {
36 | _cache = new ConcurrentDictionary();
37 | }
38 |
39 | ///
40 | /// 初始化连接
41 | ///
42 | ///
43 | ///
44 | public static void Init(string sectionName, string connectionStr)
45 | {
46 | var old = Get(sectionName);
47 |
48 | if (old == null)
49 |
50 | new SERedisConnectionDefender(sectionName, connectionStr).FreeAndConnect();
51 | }
52 |
53 |
54 | #region by section
55 |
56 |
57 | ///
58 | /// 添加或更新连接
59 | ///
60 | ///
61 | ///
62 | public static void Set(string sectionName, RedisConnection cnn)
63 | {
64 | _cache.AddOrUpdate(sectionName, cnn, (k, v) => cnn);
65 | }
66 |
67 |
68 |
69 | ///
70 | /// 是否存在
71 | ///
72 | ///
73 | ///
74 | public static bool Exists(string sectionName)
75 | {
76 | return _cache.ContainsKey(sectionName);
77 | }
78 |
79 | ///
80 | /// 获取连接
81 | ///
82 | ///
83 | ///
84 | public static RedisConnection Get(string sectionName)
85 | {
86 | if (_cache.TryGetValue(sectionName, out RedisConnection cnn))
87 | {
88 | return cnn;
89 | }
90 | return null;
91 | }
92 |
93 | ///
94 | /// 移除连接
95 | ///
96 | ///
97 | public static void Remove(string sectionName)
98 | {
99 | _cache.TryRemove(sectionName, out RedisConnection cnn);
100 | }
101 |
102 | #endregion
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisConnectionDefender.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis.Core
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis.Core
6 | *类 名 称:SERedisConnectionDefender
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/6/30 9:53:54
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/6/30 9:53:54
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using StackExchange.Redis;
19 | using System;
20 | using System.Collections.Generic;
21 | using System.Threading;
22 |
23 | namespace Wenli.Drive.Redis.Core
24 | {
25 | ///
26 | /// 连接维护类
27 | ///
28 | internal class SERedisConnectionDefender
29 | {
30 | string _sectionName = string.Empty;
31 |
32 | string _connectStr = string.Empty;
33 |
34 | ///
35 | /// 连接维护类
36 | ///
37 | ///
38 | ///
39 | public SERedisConnectionDefender(string sectionName, string connectStr)
40 | {
41 | _sectionName = sectionName;
42 |
43 | _connectStr = connectStr;
44 | }
45 |
46 | ///
47 | /// 建立连接并释放旧连接
48 | ///
49 | ///
50 | ///
51 | internal RedisConnection FreeAndConnect(RedisConnection old = null)
52 | {
53 | SERedisConnectionDefenderEx.AutoResetEvent.WaitOne();
54 |
55 | try
56 | {
57 | if (old != null && old.Connection != null && !old.Repairing) return old;
58 |
59 | #region 延迟修复
60 |
61 | if (SERedisConnectionDefenderEx.Repaired.ContainsKey(_sectionName))
62 | {
63 | if (SERedisConnectionDefenderEx.Repaired[_sectionName].Created.AddMinutes(1) < DateTime.Now)
64 | {
65 | SERedisConnectionDefenderEx.Repaired.Remove(_sectionName);
66 | }
67 | }
68 |
69 | if (SERedisConnectionDefenderEx.Repaired.ContainsKey(_sectionName))
70 | {
71 | return old;
72 | }
73 |
74 | #endregion
75 |
76 | //LogCom.WriteInfoLog($"{_sectionName}正在进入连接修复中", _connectStr);
77 |
78 | DisConnect(old);
79 |
80 | return Connect(old);
81 | }
82 | catch (Exception ex)
83 | {
84 | throw new Exception("SERedisConnectionDefender.FreeAndConnect 异常,connectStr:" + _connectStr, ex);
85 | }
86 | finally
87 | {
88 | SERedisConnectionDefenderEx.AutoResetEvent.Set();
89 | }
90 | }
91 |
92 | ///
93 | /// 建立连接
94 | ///
95 | ///
96 | RedisConnection Connect(RedisConnection old = null)
97 | {
98 | try
99 | {
100 | if (old == null)
101 | {
102 | old = new RedisConnection() { Connection = ConnectionMultiplexer.Connect(_connectStr), Repairing = false };
103 | }
104 | else
105 | {
106 | old.Connection = ConnectionMultiplexer.Connect(_connectStr);
107 |
108 | old.Repairing = false;
109 | }
110 |
111 | SERedisConnectionDefenderEx.Repaired[_sectionName] = new SectionInfo
112 | {
113 | SectionName = _sectionName,
114 | Created = DateTime.Now
115 | };
116 |
117 | SERedisConnectionCache.Set(_sectionName, old);
118 |
119 | return old;
120 | }
121 | catch (Exception ex)
122 | {
123 | throw new Exception("SERedisConnectionDefender.Connect 异常,connectStr:" + _connectStr, ex);
124 | }
125 | }
126 |
127 | ///
128 | /// 释放连接
129 | ///
130 | ///
131 | void DisConnect(RedisConnection old = null)
132 | {
133 | if (old == null) return;
134 |
135 | SERedisConnectionCache.Remove(_sectionName);
136 |
137 | old.Connection.Close();
138 |
139 | old.Connection.Dispose();
140 |
141 | old.Connection = null;
142 | }
143 | }
144 |
145 | ///
146 | /// SERedisConnectionDefender的辅助类,仅限SERedisConnectionDefender.GetConnection方法中使用
147 | ///
148 | internal static class SERedisConnectionDefenderEx
149 | {
150 | internal static Dictionary Repaired { get; set; } = new Dictionary();
151 |
152 | internal static AutoResetEvent AutoResetEvent { get; set; } = new AutoResetEvent(true);
153 | }
154 |
155 | ///
156 | /// section配置
157 | ///
158 | class SectionInfo
159 | {
160 | public string SectionName { get; set; }
161 |
162 | public DateTime Created { get; set; }
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisHelper.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2016-2020
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:1cc1fa2b-c8c8-4627-bb40-dece98f2b73a
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:Wenli.Drive.Redis
10 | * 命名空间:Wenli.Drive.Redis
11 | * 创建时间:2016/12/28 9:59:30
12 | * 创建人:wenli
13 | * 创建说明:
14 | *****************************************************************************************************/
15 | using System;
16 | using System.Collections.Concurrent;
17 | using Wenli.Drive.Redis.Interface;
18 |
19 | namespace Wenli.Drive.Redis.Core
20 | {
21 | ///
22 | /// SERedis操作处理类
23 | ///
24 | [Serializable]
25 | public class SERedisHelper : IRedisHelper, IDisposable
26 | {
27 | ///
28 | /// 哨兵监听集合
29 | ///
30 | private static readonly ConcurrentDictionary _SentinelPool =
31 | new ConcurrentDictionary();
32 |
33 | private static object _LockObj = new object();
34 |
35 | private int _BusyRetry = 5;
36 |
37 | private int _BusyRetryWaitMS = 200;
38 |
39 | private IRedisOperation _RedisOperation;
40 |
41 | //实例名称
42 | private string _sectionName;
43 |
44 | private static object locker = new object();
45 |
46 |
47 | ///
48 | /// 释放
49 | ///
50 | public void Dispose()
51 | {
52 | _RedisOperation = null;
53 | }
54 |
55 | ///
56 | /// 初始化池,类似于构造方法
57 | /// 不要重复调用
58 | ///
59 | ///
60 | ///
61 | public void Init(string section)
62 | {
63 | Init(RedisConfig.GetConfig(section));
64 | }
65 |
66 | ///
67 | /// 初始化
68 | ///
69 | ///
70 | ///
71 | ///
72 | ///
73 | ///
74 | public void Init(string sectionName, RedisConnectType type, string master, string password = "", string serviceName = "")
75 | {
76 | var redisConfig = new RedisConfig()
77 | {
78 | SectionName = sectionName,
79 | Type = type,
80 | Masters = master
81 | };
82 | if (!string.IsNullOrEmpty(serviceName))
83 | {
84 | redisConfig.ServiceName = serviceName;
85 | }
86 | if (!string.IsNullOrEmpty(password))
87 | {
88 | redisConfig.Password = password;
89 | }
90 | this.Init(redisConfig);
91 | }
92 |
93 |
94 | ///
95 | /// redis操作
96 | ///
97 | ///
98 | ///
99 | public IRedisOperation GetRedisOperation(int dbIndex = -1)
100 | {
101 | return new SERedisOperation(_sectionName, dbIndex);
102 | }
103 |
104 | ///
105 | /// 初始化池,类似于构造方法
106 | /// 不要重复调用
107 | ///
108 | ///
109 | public void Init(RedisConfig redisConfig)
110 | {
111 | if (redisConfig == null)
112 | throw new Exception("传入的redisConfig实例不能空");
113 | _sectionName = redisConfig.SectionName;
114 | _BusyRetry = redisConfig.BusyRetry;
115 | _BusyRetryWaitMS = redisConfig.BusyRetryWaitMS;
116 | if (string.IsNullOrWhiteSpace(_sectionName))
117 | throw new Exception("redisConfig.SectionName不能为空");
118 |
119 | lock (locker)
120 | {
121 | if (SERedisConnectionCache.Exists(_sectionName))
122 | return;
123 |
124 | var configStr = GenerateConnectionString(redisConfig);
125 |
126 | if ((redisConfig.PoolSize < 1) || (redisConfig.PoolSize > 100))
127 | redisConfig.PoolSize = 1;
128 |
129 | //哨兵特殊处理
130 | if (redisConfig.Type == RedisConnectType.Sentinel)
131 | {
132 | var sentinel = new SESentinelClient(_sectionName, configStr, redisConfig.PoolSize, redisConfig.Password);
133 |
134 | sentinel.OnRedisServerChanged += sentinel_OnRedisServerChanged;
135 |
136 | var operateRedisConnecitonString = sentinel.Start();
137 |
138 | _SentinelPool.AddOrUpdate(_sectionName + "_" + redisConfig.ServiceName, sentinel, (x, y) => sentinel);
139 |
140 | SERedisConnectionCache.Init(_sectionName, operateRedisConnecitonString);
141 | }
142 | else
143 | {
144 | SERedisConnectionCache.Init(_sectionName, configStr);
145 | }
146 | }
147 | }
148 |
149 | ///
150 | /// 根据redis使用类型来生成相应的连接字符串
151 | ///
152 | ///
153 | ///
154 | private static string GenerateConnectionString(RedisConfig redisConfig)
155 | {
156 | var configStr = string.Empty;
157 |
158 | switch ((RedisConnectType)redisConfig.Type)
159 | {
160 | case RedisConnectType.Instance:
161 | if (!string.IsNullOrWhiteSpace(redisConfig.Slaves))
162 | configStr = string.Format("{0},{1},defaultDatabase={2}", redisConfig.Masters, redisConfig.Slaves, redisConfig.DefaultDatabase);
163 | else
164 | configStr = string.Format("{0},defaultDatabase={1}", redisConfig.Masters, redisConfig.DefaultDatabase);
165 | if (!string.IsNullOrWhiteSpace(redisConfig.Password))
166 | configStr += ",password=" + redisConfig.Password;
167 | break;
168 | case RedisConnectType.Sentinel:
169 | //哨兵
170 | configStr = string.Format("{0},defaultDatabase={1},serviceName={2}", redisConfig.Masters, redisConfig.DefaultDatabase, redisConfig.ServiceName);
171 | break;
172 | case RedisConnectType.Cluster:
173 | //集群
174 | configStr = string.Format("{0}", redisConfig.Masters);
175 | if (!string.IsNullOrWhiteSpace(redisConfig.Password))
176 | configStr += ",password=" + redisConfig.Password;
177 | break;
178 | default:
179 | if (!string.IsNullOrWhiteSpace(redisConfig.Slaves))
180 | configStr = redisConfig.Masters + "," + redisConfig.Slaves;
181 | else
182 | configStr = redisConfig.Masters;
183 |
184 | if (!string.IsNullOrWhiteSpace(redisConfig.Password))
185 | configStr += ",password=" + redisConfig.Password;
186 | break;
187 | }
188 | configStr +=
189 | string.Format(",allowAdmin={0},connectRetry={1},connectTimeout={2},keepAlive={3},syncTimeout={4},responseTimeout={4},abortConnect=false", redisConfig.AllowAdmin, redisConfig.ConnectRetry, redisConfig.ConnectTimeout, redisConfig.KeepAlive, redisConfig.CommandTimeout);
190 |
191 | if (!string.IsNullOrWhiteSpace(redisConfig.Extention))
192 | {
193 | configStr += "," + redisConfig.Extention;
194 | }
195 |
196 | return configStr;
197 | }
198 |
199 |
200 | ///
201 | /// 哨兵监测事件
202 | ///
203 | ///
204 | ///
205 | private void sentinel_OnRedisServerChanged(string section, string newConnectionString)
206 | {
207 | SERedisConnectionCache.Init(_sectionName, newConnectionString);
208 | }
209 | }
210 | }
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisLock.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using Wenli.Drive.Redis.Interface;
4 |
5 | namespace Wenli.Drive.Redis.Core
6 | {
7 | public partial class SERedisOperation : IRedisOperation
8 | {
9 | private static readonly string _prex = "lock_";
10 |
11 | int _timeout = 30 * 1000;
12 |
13 | string _key = string.Empty;
14 |
15 | string GetKey(string key)
16 | {
17 | return _prex + key;
18 | }
19 |
20 | ///
21 | /// 利用StringSetIfNotExists实现锁
22 | ///
23 | ///
24 | /// 过期时间(毫秒)
25 | ///
26 | ///
27 | public bool Lock(string key, int timeout = 30 * 1000, int rolling = 50)
28 | {
29 | _key = key;
30 |
31 | _timeout = timeout;
32 |
33 | var ts = TimeSpan.FromMilliseconds(_timeout);
34 |
35 | String expiresStr = DateTime.Now.Add(ts).Ticks.ToString();
36 |
37 | while (_timeout > rolling)
38 | {
39 | if (this.StringSetIfNotExists(GetKey(_key), expiresStr, ts))
40 | {
41 | return true;
42 | }
43 | timeout -= rolling;
44 | Thread.Sleep(rolling);
45 | }
46 | return false;
47 | }
48 |
49 | ///
50 | /// 移除lock
51 | ///
52 | ///
53 | public void UnLock(string key = "")
54 | {
55 | if (string.IsNullOrEmpty(key))
56 | {
57 | key = _key;
58 | }
59 |
60 | this.KeyDelete(GetKey(key));
61 | }
62 |
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisOperation.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2016-2020
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:1cc1fa2b-c8c8-4627-bb40-dece98f2b73a
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:Wenli.Drive.Redis
10 | * 命名空间:Wenli.Drive.Redis
11 | * 创建时间:2016/12/28 9:59:30
12 | * 创建人:wenli
13 | * 创建说明:
14 | *****************************************************************************************************/
15 | using System;
16 | using System.Collections.Generic;
17 | using Wenli.Drive.Redis.Interface;
18 | using Wenli.Drive.Redis.Tool;
19 |
20 | namespace Wenli.Drive.Redis.Core
21 | {
22 | ///
23 | /// SERedis操作类
24 | ///
25 | public partial class SERedisOperation : IRedisOperation
26 | {
27 | ///
28 | /// 倒序排例
29 | ///
30 | private const string DefaultOrder = "descending";
31 |
32 | private readonly int _dbIndex = -1;
33 |
34 | private readonly string _sectionName;
35 |
36 | SERedisConnection _cnn = null;
37 |
38 | ///
39 | /// SERedis操作类
40 | ///
41 | ///
42 | ///
43 | ///
44 | ///
45 | public SERedisOperation(string sectionName, int dbIndex = -1, int busyRetry = 1000, int busyRetryWaitMS = 200)
46 | {
47 | _sectionName = sectionName;
48 | _dbIndex = dbIndex;
49 | _cnn = new SERedisConnection(_sectionName, _dbIndex);
50 | }
51 |
52 | #region 操作方法重试包装
53 |
54 | private T DoWithRetry(Func func)
55 | {
56 | try
57 | {
58 | if (_cnn.RedisConnection.Repairing) throw new Exception($"SERedisOperation操作失败,sectionName:{_sectionName},_cnn:{SerializeHelper.Serialize(_cnn)}", new Exception("连接正在修复中"));
59 |
60 | return func();
61 | }
62 | catch (Exception ex)
63 | {
64 | if (ex.Message.IndexOf("SERedisOperation操作失败") > -1) throw ex;
65 |
66 | if (!_cnn.RedisConnection.Repairing)
67 | {
68 | _cnn.TryRepairConnection();
69 | }
70 | throw new Exception($"SERedisOperation操作失败,sectionName:{_sectionName},_cnn:{SerializeHelper.Serialize(_cnn)}", ex);
71 | }
72 | }
73 |
74 | private void DoWithRetry(Action action)
75 | {
76 | try
77 | {
78 | if (_cnn.RedisConnection.Repairing) throw new Exception($"SERedisOperation操作失败,sectionName:{_sectionName},_cnn:{SerializeHelper.Serialize(_cnn)}", new Exception("连接正在修复中"));
79 |
80 | action();
81 | }
82 | catch (Exception ex)
83 | {
84 | if (ex.Message.IndexOf("SERedisOperation操作失败") > -1) throw ex;
85 |
86 | if (!_cnn.RedisConnection.Repairing)
87 | {
88 | _cnn.TryRepairConnection();
89 | }
90 | throw new Exception($"SERedisOperation操作失败,sectionName:{_sectionName},_cnn:{SerializeHelper.Serialize(_cnn)}", ex);
91 | }
92 | }
93 |
94 | #endregion
95 |
96 | ///
97 | /// Ping
98 | ///
99 | ///
100 | public TimeSpan Ping()
101 | {
102 | return DoWithRetry(() =>
103 | {
104 | return _cnn.GetDatabase().Ping();
105 | });
106 | }
107 |
108 | ///
109 | /// 创建批量处理
110 | ///
111 | ///
112 | public RedisBatcher CreateBatcher()
113 | {
114 | return _cnn.CreateBatcher();
115 | }
116 |
117 | ///
118 | /// 获取keys
119 | ///
120 | ///
121 | ///
122 | ///
123 | ///
124 | public List Keys(int dbIndex = -1, string patten = "*", int count = 20)
125 | {
126 | return DoWithRetry(() =>
127 | {
128 | return _cnn.Keys(dbIndex, patten, count);
129 | });
130 | }
131 |
132 | }
133 | }
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisOperationForHash.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis
6 | *类 名 称:SERedisOperationForHash
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/6/3 15:46:25
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/6/3 15:46:25
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using StackExchange.Redis;
19 | using System;
20 | using System.Collections.Generic;
21 | using System.Linq;
22 | using Wenli.Drive.Redis.Extends;
23 | using Wenli.Drive.Redis.Interface;
24 | using Wenli.Drive.Redis.Tool;
25 |
26 | namespace Wenli.Drive.Redis.Core
27 | {
28 | ///
29 | /// SERedisOperationForHash
30 | ///
31 | public partial class SERedisOperation : IRedisOperation
32 | {
33 | #region Hashes
34 |
35 | ///
36 | /// 检查hash
37 | ///
38 | ///
39 | ///
40 | ///
41 | public bool HashExists(string hashId, string key)
42 | {
43 | return DoWithRetry(() =>
44 | {
45 | try
46 | {
47 | return _cnn.GetDatabase().HashExists(hashId, key);
48 | }
49 | catch (Exception ex)
50 | {
51 | throw new Exception(string.Format("HashExists异常,参数:{0},{1},{2},{3},异常信息:{4}", _sectionName, _dbIndex, hashId, key, ex.Message));
52 | }
53 | });
54 | }
55 |
56 | ///
57 | /// 设置hash
58 | ///
59 | ///
60 | ///
61 | ///
62 | ///
63 | ///
64 | public bool HashSet(string hashId, string key, T t) where T : class, new()
65 | {
66 | return DoWithRetry(() =>
67 | {
68 | return _cnn.GetDatabase().HashSet(hashId, key, SerializeHelper.Serialize(t));
69 | });
70 | }
71 |
72 | ///
73 | /// 设置hash
74 | ///
75 | ///
76 | ///
77 | ///
78 | ///
79 | ///
80 | public bool HashSet(string hashId, string key, string val)
81 | {
82 | return DoWithRetry(() =>
83 | {
84 | return _cnn.GetDatabase().HashSet(hashId, key, val);
85 | });
86 | }
87 |
88 | ///
89 | /// 在一个hash中设置一个key - value,仅仅当不存在的时候才设置
90 | ///
91 | ///
92 | ///
93 | ///
94 | ///
95 | ///
96 | public bool HashSetIfNotExists(string hashId, string key, string value)
97 | {
98 | return DoWithRetry(() =>
99 | {
100 | return _cnn.GetDatabase().HashSet(hashId, key, value, When.NotExists);
101 | });
102 | }
103 |
104 | ///
105 | /// 移除hash
106 | ///
107 | ///
108 | ///
109 | ///
110 | public bool HashDelete(string hashId, string key)
111 | {
112 | return DoWithRetry(() =>
113 | {
114 | return _cnn.GetDatabase().HashDelete(hashId, key);
115 | });
116 | }
117 |
118 | ///
119 | /// 批量移除hash
120 | ///
121 | ///
122 | ///
123 | ///
124 | public long HashDelete(string hashId, string[] keys)
125 | {
126 | return DoWithRetry(() =>
127 | {
128 | var hkeys = new RedisValue[keys.Length];
129 |
130 | for (int i = 0; i < keys.Length; i++)
131 | {
132 | hkeys[i] = keys[i];
133 | }
134 | return _cnn.GetDatabase().HashDelete(hashId, hkeys);
135 | });
136 | }
137 |
138 | ///
139 | /// hash计数器
140 | ///
141 | ///
142 | ///
143 | ///
144 | ///
145 | public long HashIncrement(string hashId, string key, long value = 1)
146 | {
147 | return DoWithRetry(() =>
148 | {
149 | return _cnn.GetDatabase().HashIncrement(hashId, key, value);
150 | });
151 | }
152 |
153 | ///
154 | /// 获取hash
155 | ///
156 | ///
157 | ///
158 | ///
159 | ///
160 | public T HashGet(string hashId, string key) where T : class, new()
161 | {
162 | return DoWithRetry(() =>
163 | {
164 | return _cnn.GetDatabase().HashGet(hashId, key).ConvertTo();
165 | });
166 | }
167 |
168 | ///
169 | /// 获取hash
170 | ///
171 | ///
172 | ///
173 | ///
174 | public string HashGet(string hashId, string key)
175 | {
176 | return DoWithRetry(() =>
177 | {
178 | return _cnn.GetDatabase().HashGet(hashId, key).ToString();
179 | });
180 | }
181 |
182 | ///
183 | /// 获取hash数量
184 | ///
185 | ///
186 | ///
187 | public long GetHashCount(string hashId)
188 | {
189 | return DoWithRetry(() =>
190 | {
191 | return _cnn.GetDatabase().HashLength(hashId);
192 | });
193 | }
194 |
195 | ///
196 | /// 获取某个hashid下面全部hash
197 | ///
198 | ///
199 | ///
200 | public List HashGetAll(string hashId)
201 | {
202 | return DoWithRetry(() =>
203 | {
204 | var result = new List();
205 | var list = _cnn.GetDatabase().HashValues(hashId).ToList();
206 | if ((list != null) && (list.Count > 0))
207 | list.ForEach(x =>
208 | {
209 | if (x.HasValue)
210 | result.Add(x.ToString());
211 | });
212 | return result;
213 | });
214 | }
215 |
216 | ///
217 | /// 获取某个hashid下面全部hash
218 | ///
219 | ///
220 | ///
221 | ///
222 | public List HashGetAll(string hashId) where T : class, new()
223 | {
224 | return DoWithRetry(() =>
225 | {
226 | return _cnn.GetDatabase().HashValues(hashId).ToList().ConvertTo();
227 | });
228 | }
229 |
230 | ///
231 | /// 获取全部的hashkey,hashvalue字典
232 | ///
233 | ///
234 | ///
235 | ///
236 | public Dictionary HashGetAllDic(string hashId) where T : class, new()
237 | {
238 | return DoWithRetry(() =>
239 | {
240 | return _cnn.GetDatabase().HashGetAll(hashId).ConvertTo();
241 | });
242 | }
243 |
244 | ///
245 | /// 获取全部的hashkey,hashvalue字典
246 | ///
247 | ///
248 | ///
249 | public Dictionary HashGetAllDic(string hashId)
250 | {
251 | return DoWithRetry(() =>
252 | {
253 | return _cnn.GetDatabase().HashGetAll(hashId).ConvertTo();
254 | });
255 | }
256 |
257 | ///
258 | /// 分页某个hashid下面hash
259 | ///
260 | ///
261 | ///
262 | ///
263 | ///
264 | ///
265 | public List HashGetAll(string hashID, int pageIndex, int pageSize) where T : class, new()
266 | {
267 | return DoWithRetry(() =>
268 | {
269 | var result = new List();
270 | pageIndex = pageIndex > 0 ? pageIndex : 1;
271 | pageSize = pageSize > 0 ? pageSize : 20;
272 | var list =
273 | _cnn.GetDatabase().HashValues(hashID).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
274 | if ((list != null) && (list.Count > 0))
275 | list.ForEach(value =>
276 | {
277 | if (!string.IsNullOrEmpty(value) && value.HasValue)
278 | {
279 | var obj = SerializeHelper.Deserialize(value.ToString());
280 | if (obj != null)
281 | result.Add(obj);
282 | }
283 | });
284 | return result;
285 | });
286 | }
287 |
288 | ///
289 | /// 获取指定的全部hashlist
290 | ///
291 | ///
292 | ///
293 | ///
294 | public List HashGetAll(List hashIds) where T : class, new()
295 | {
296 | return DoWithRetry(() =>
297 | {
298 | var result = new List();
299 | foreach (var hashId in hashIds)
300 | {
301 | var list = HashGetAll(hashId);
302 | if ((list != null) && (list.Count > 0))
303 | result.AddRange(list);
304 | }
305 | return result;
306 | });
307 | }
308 |
309 | ///
310 | /// 获取某个hashid下面全部keys
311 | ///
312 | ///
313 | ///
314 | public List GetHashKeys(string hashId)
315 | {
316 | return DoWithRetry(() =>
317 | {
318 | return _cnn.GetDatabase().HashKeys(hashId).ConvertTo();
319 | });
320 | }
321 |
322 | ///
323 | /// 从指定hashid,keys中获取指定hash集合
324 | ///
325 | ///
326 | ///
327 | ///
328 | ///
329 | public List GetValuesFromHash(string hashId, List keys) where T : class, new()
330 | {
331 | return DoWithRetry(() =>
332 | {
333 | var list = new List();
334 | if ((keys != null) && (keys.Count > 0))
335 | {
336 | var rv = new RedisValue[keys.Count];
337 | for (var i = 0; i < keys.Count; i++)
338 | rv[i] = keys[i];
339 | var vlts = _cnn.GetDatabase().HashGet(hashId, rv).ConvertTo();
340 | list.AddRange(vlts);
341 | }
342 | return list;
343 | });
344 | }
345 |
346 | ///
347 | /// 从指定hashid,keys中获取指定hash集合
348 | ///
349 | ///
350 | ///
351 | ///
352 | ///
353 | public Dictionary GetValuesDicFromHash(string hashId, List keys) where T : class, new()
354 | {
355 | return DoWithRetry(() =>
356 | {
357 | var dic = new Dictionary();
358 | if ((keys != null) && (keys.Count > 0))
359 | {
360 | var rv = new RedisValue[keys.Count];
361 | for (var i = 0; i < keys.Count; i++)
362 | rv[i] = keys[i];
363 | var vlts = _cnn.GetDatabase().HashGet(hashId, rv);
364 | for (int i = 0; i < vlts.Length; i++)
365 | if (!string.IsNullOrEmpty(vlts[i]))
366 | {
367 | var obj = SerializeHelper.Deserialize(vlts[i]);
368 | if (obj != null)
369 | dic.Add(rv[i], obj);
370 | }
371 | }
372 | return dic;
373 | });
374 | }
375 | ///
376 | /// 从指定hashid,keys中获取指定hash集合
377 | ///
378 | ///
379 | ///
380 | ///
381 | public List GetValuesFromHash(string hashId, List keys)
382 | {
383 | return DoWithRetry(() =>
384 | {
385 | var list = new List();
386 | if ((keys != null) && (keys.Count > 0))
387 | {
388 | var rv = new RedisValue[keys.Count];
389 | for (var i = 0; i < keys.Count; i++)
390 | rv[i] = keys[i];
391 | var vlts = _cnn.GetDatabase().HashGet(hashId, rv);
392 | foreach (var val in vlts)
393 | if (!string.IsNullOrEmpty(val) && val.HasValue)
394 | list.Add(val);
395 | }
396 | return list;
397 | });
398 | }
399 |
400 | #endregion
401 | }
402 | }
403 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisOperationForList.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis.Core
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis.Core
6 | *类 名 称:SERedisOperationForList
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/6/3 15:50:38
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/6/3 15:50:38
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using StackExchange.Redis;
19 | using System;
20 | using System.Collections.Generic;
21 | using System.Linq;
22 | using Wenli.Drive.Redis.Interface;
23 | using Wenli.Drive.Redis.Tool;
24 |
25 | namespace Wenli.Drive.Redis.Core
26 | {
27 | ///
28 | /// SERedisOperationForList
29 | ///
30 | public partial class SERedisOperation : IRedisOperation
31 | {
32 | #region Lists
33 |
34 | ///
35 | /// 进队
36 | ///
37 | ///
38 | ///
39 | public void Enqueue(string listId, string value)
40 | {
41 | DoWithRetry(() =>
42 | {
43 | _cnn.GetDatabase().ListLeftPush(listId, value);
44 | });
45 | }
46 |
47 | ///
48 | /// 进队
49 | ///
50 | ///
51 | ///
52 | public long Enqueue(string listId, List values)
53 | {
54 | if (values == null || values.Count == 0)
55 | {
56 | return 0;
57 | }
58 |
59 | return DoWithRetry(() =>
60 | {
61 | return _cnn.GetDatabase().ListLeftPush(listId, values.Select(r => (RedisValue)r).ToArray());
62 | });
63 | }
64 |
65 | ///
66 | /// 出队
67 | ///
68 | ///
69 | ///
70 | public string Dnqueue(string listId)
71 | {
72 | return DoWithRetry(() =>
73 | {
74 | string result = _cnn.GetDatabase().ListRightPop(listId);
75 |
76 | if (!string.IsNullOrEmpty(result))
77 | {
78 | return result;
79 | }
80 |
81 | result = _cnn.GetDatabase().ListRightPop(listId);
82 |
83 | if (!string.IsNullOrEmpty(result))
84 | {
85 | return result;
86 | }
87 |
88 | return null;
89 | });
90 | }
91 |
92 | ///
93 | /// 进队
94 | ///
95 | ///
96 | ///
97 | ///
98 | public void Enqueue(string listId, T t) where T : class, new()
99 | {
100 | DoWithRetry(() =>
101 | {
102 | var value = SerializeHelper.Serialize(t);
103 | _cnn.GetDatabase().ListLeftPush(listId, value);
104 | });
105 | }
106 |
107 | ///
108 | /// 出队
109 | ///
110 | ///
111 | ///
112 | ///
113 | public T Dnqueue(string listId) where T : class, new()
114 | {
115 | return DoWithRetry(() =>
116 | {
117 | var json = _cnn.GetDatabase().ListRightPop(listId);
118 | if (json.IsNullOrEmpty)
119 | return default(T);
120 | return SerializeHelper.Deserialize(json.ToString());
121 | });
122 | }
123 |
124 | ///
125 | /// 获取队列元素
126 | ///
127 | ///
128 | ///
129 | ///
130 | ///
131 | ///
132 | public List GetList(string listId, long start = 0, long stop = -1) where T : class, new()
133 | {
134 | return DoWithRetry(() =>
135 | {
136 | var result = new List();
137 | var list = _cnn.GetDatabase().ListRange(listId, start, stop).ToList();
138 | if (list.Count > 0)
139 | list.ForEach(x =>
140 | {
141 | if (x.HasValue)
142 | {
143 | var value = SerializeHelper.Deserialize(x);
144 | result.Add(value);
145 | }
146 | });
147 | return result;
148 | });
149 | }
150 |
151 | ///
152 | /// 获取队列长度
153 | ///
154 | ///
155 | ///
156 | public long QueueCount(string listId)
157 | {
158 | return DoWithRetry(() =>
159 | {
160 | return _cnn.GetDatabase().ListLength(listId);
161 | });
162 | }
163 | ///
164 | /// 从出队方向入队
165 | ///
166 | ///
167 | ///
168 | public void REnqueue(string listId, string value)
169 | {
170 | DoWithRetry(() =>
171 | {
172 | _cnn.GetDatabase().ListRightPush(listId, value);
173 | });
174 | }
175 | ///
176 | /// 从出队方向入队
177 | ///
178 | ///
179 | ///
180 | ///
181 | public void REnqueue(string listId, T t) where T : class, new()
182 | {
183 | DoWithRetry(() =>
184 | {
185 | var value = SerializeHelper.Serialize(t);
186 | _cnn.GetDatabase().ListRightPush(listId, value);
187 | });
188 | }
189 |
190 | #endregion
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisOperationForSet.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis.Core
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis.Core
6 | *类 名 称:SERedisOperationForSet
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/6/3 15:48:09
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/6/3 15:48:09
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using Wenli.Drive.Redis.Extends;
19 | using Wenli.Drive.Redis.Interface;
20 | using System.Collections.Generic;
21 | using System.Linq;
22 |
23 | namespace Wenli.Drive.Redis.Core
24 | {
25 | ///
26 | /// SERedisOperationForSet
27 | ///
28 | public partial class SERedisOperation : IRedisOperation
29 | {
30 | #region Set
31 |
32 | ///
33 | /// 添加一个set
34 | ///
35 | ///
36 | ///
37 | ///
38 | public bool SetAdd(string setId, string val)
39 | {
40 | return DoWithRetry(() =>
41 | {
42 | return _cnn.GetDatabase().SetAdd(setId, val);
43 | });
44 | }
45 |
46 | ///
47 | /// 是否存在于set中
48 | ///
49 | ///
50 | ///
51 | ///
52 | public bool SetContains(string setId, string val)
53 | {
54 | return DoWithRetry(() =>
55 | {
56 | return _cnn.GetDatabase().SetContains(setId, val);
57 | });
58 | }
59 |
60 | ///
61 | /// 获取某个key下面全部的value
62 | ///
63 | ///
64 | ///
65 | public List SetMembers(string setId)
66 | {
67 | return DoWithRetry(() =>
68 | {
69 | return _cnn.GetDatabase().SetMembers(setId).ConvertTo();
70 | });
71 | }
72 |
73 | ///
74 | /// 移除set
75 | ///
76 | ///
77 | ///
78 | ///
79 | public bool SetRemove(string setId, string val)
80 | {
81 | return DoWithRetry(() =>
82 | {
83 | return _cnn.GetDatabase().SetRemove(setId, val);
84 | });
85 | }
86 |
87 | ///
88 | /// 批量删除set
89 | ///
90 | ///
91 | ///
92 | public void SetsRemove(string setId, string[] vals)
93 | {
94 | DoWithRetry(() =>
95 | {
96 | for (var i = 0; i < vals.Length; i++)
97 | _cnn.GetDatabase().SetRemove(setId, vals[i]);
98 | });
99 | }
100 |
101 | ///
102 | /// 返回指定set长度
103 | ///
104 | ///
105 | ///
106 | public long SetLength(string setId)
107 | {
108 | return DoWithRetry(() =>
109 | {
110 | return _cnn.GetDatabase().SetLength(setId);
111 | });
112 | }
113 |
114 | #endregion
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisOperationForSortedSet.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis.Core
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis.Core
6 | *类 名 称:SERedisOperationForSortedSet
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/6/3 15:49:14
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/6/3 15:49:14
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using StackExchange.Redis;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using Wenli.Drive.Redis.Data;
22 | using Wenli.Drive.Redis.Extends;
23 | using Wenli.Drive.Redis.Interface;
24 |
25 | namespace Wenli.Drive.Redis.Core
26 | {
27 | ///
28 | /// SERedisOperationForSortedSet
29 | ///
30 | public partial class SERedisOperation : IRedisOperation
31 | {
32 | #region Sorted Sets
33 |
34 | ///
35 | /// 检查SortedSet
36 | ///
37 | ///
38 | ///
39 | ///
40 | public bool SortedSetItemIsExist(string setId, string item)
41 | {
42 | return DoWithRetry(() =>
43 | {
44 | var value = GetItemScoreFromSortedSet(setId, item);
45 | if (value != null)
46 | return true;
47 | return false;
48 | });
49 | }
50 |
51 | ///
52 | /// 添加SortedSet
53 | ///
54 | ///
55 | ///
56 | ///
57 | ///
58 | ///
59 | public bool SortedSetAdd(string setId, string item, double score)
60 | {
61 | return DoWithRetry(() =>
62 | {
63 | return _cnn.GetDatabase().SortedSetAdd(setId, item, score);
64 | });
65 | }
66 |
67 | ///
68 | /// 查询SortedSet集合
69 | ///
70 | ///
71 | ///
72 | ///
73 | ///
74 | ///
75 | public List GetSortedSetRangeByRank(string setId, long fromRank, long toRank,
76 | string order = DefaultOrder)
77 | {
78 | return DoWithRetry(() =>
79 | {
80 | return _cnn.GetDatabase()
81 | .SortedSetRangeByRank(setId, fromRank, toRank,
82 | order == Order.Descending.ToString().ToLower() ? Order.Descending : Order.Ascending)
83 | .ToList().ConvertTo();
84 | });
85 | }
86 |
87 | ///
88 | /// 根据score查询SortedSet集合
89 | ///
90 | ///
91 | ///
92 | ///
93 | ///
94 | ///
95 | public Dictionary GetSortedSetRangeByRankWithScores(string setId, long fromRank, long toRank,
96 | string order = DefaultOrder)
97 | {
98 | return DoWithRetry(() =>
99 | {
100 | return _cnn.GetDatabase()
101 | .SortedSetRangeByRankWithScores(setId, fromRank, toRank,
102 | order == Order.Descending.ToString().ToLower() ? Order.Descending : Order.Ascending)
103 | .ToList().ConvertTo();
104 | });
105 | }
106 |
107 | ///
108 | /// 获取SortedSet集合区间
109 | ///
110 | ///
111 | /// 最小score
112 | /// 最大score
113 | ///
114 | ///
115 | ///
116 | ///
117 | public PagedList GetSortedSetRangeByRankWithSocres(string setid, long min, long max, int pageIndex = 1,
118 | int pageSize = 20, bool orderBy = true)
119 | {
120 | return DoWithRetry(() =>
121 | {
122 | var count = _cnn.GetDatabase().SortedSetLength(setid); //此处无法正确获取数量
123 | if (count > 0)
124 | {
125 | var list = _cnn.GetDatabase()
126 | .SortedSetRangeByScoreWithScores(setid, min, max, Exclude.Stop,
127 | orderBy ? Order.Ascending : Order.Descending, (pageIndex - 1) * pageSize, pageSize);
128 | if ((list != null) && (list.Length > 0))
129 | {
130 | var result = new List();
131 | list.ToList().ForEach(x =>
132 | {
133 | if ((x != null) && x.Element.HasValue)
134 | {
135 | var value = x.Element.ToString();
136 | result.Add(value);
137 | }
138 | });
139 | return new PagedList
140 | {
141 | PageIndex = pageIndex,
142 | PageSize = pageSize,
143 | Count = count,
144 | List = result
145 | };
146 | }
147 | }
148 | return new PagedList();
149 | });
150 | }
151 |
152 | ///
153 | /// 获取SortedSet集合区间
154 | ///
155 | ///
156 | ///
157 | ///
158 | ///
159 | ///
160 | ///
161 | ///
162 | public PagedList GetSortedSetRangeByRankBySocre(string setid, double minScore, double maxScore, int pageIndex = 1,
163 | int pageSize = 20, bool orderBy = true)
164 | {
165 | return DoWithRetry(() =>
166 | {
167 | var count = _cnn.GetDatabase().SortedSetLength(setid, minScore, maxScore);
168 | if (count > 0)
169 | {
170 | var list = _cnn.GetDatabase().SortedSetRangeByScore(setid, minScore, maxScore, Exclude.Stop, orderBy ? Order.Ascending : Order.Descending, (pageIndex - 1) * pageSize, pageSize);
171 |
172 | if (list != null && list.Any())
173 | {
174 | var result = new List();
175 |
176 | foreach (var item in list)
177 | {
178 | result.Add(item.ToString());
179 | }
180 |
181 | return new PagedList
182 | {
183 | PageIndex = pageIndex,
184 | PageSize = pageSize,
185 | Count = count,
186 | List = result
187 | };
188 | }
189 | }
190 | return new PagedList();
191 | });
192 | }
193 |
194 | ///
195 | /// 获取zset
196 | ///
197 | ///
198 | ///
199 | ///
200 | ///
201 | ///
202 | public Dictionary GetSortedSetRangeBySocreWithScore(string setid, double minScore, double maxScore, bool orderBy = true)
203 | {
204 | return DoWithRetry(() =>
205 | {
206 | return _cnn.GetDatabase().SortedSetRangeByScoreWithScores(setid, minScore, maxScore, Exclude.Stop, orderBy ? Order.Ascending : Order.Descending).ConvertTo();
207 | });
208 | }
209 |
210 | ///
211 | /// 获取zset
212 | ///
213 | ///
214 | ///
215 | ///
216 | ///
217 | ///
218 | ///
219 | ///
220 | public PagedDictionary GetSortedSetRangeBySocreWithScore(string setid, double minScore, double maxScore, int pageIndex, int pageSize, bool orderBy = true)
221 | {
222 | return DoWithRetry(() =>
223 | {
224 | var len = _cnn.GetDatabase().SortedSetLength(setid, minScore, maxScore, Exclude.Stop);
225 | return _cnn.GetDatabase().SortedSetRangeByScoreWithScores(setid, minScore, maxScore, Exclude.Stop, orderBy ? Order.Ascending : Order.Descending, skip: (pageIndex - 1) * pageSize, take: pageSize).ConvertTo(pageIndex, pageSize, len);
226 | });
227 | }
228 |
229 | ///
230 | /// 获取zset
231 | ///
232 | ///
233 | ///
234 | ///
235 | ///
236 | ///
237 | public List GetSortedSetRangeBySocre(string setid, double minScore, double maxScore, bool orderBy = true)
238 | {
239 | return DoWithRetry(() =>
240 | {
241 | return _cnn.GetDatabase().SortedSetRangeByScore(setid, minScore, maxScore, Exclude.Stop, orderBy ? Order.Ascending : Order.Descending).ConvertTo();
242 | });
243 | }
244 |
245 |
246 | ///
247 | /// 根据值范围获取SortedSet集合
248 | ///
249 | ///
250 | ///
251 | ///
252 | ///
253 | public List GetSortedSetRangeByValue(string setId, long minValue, long maxValue)
254 | {
255 | return DoWithRetry(() =>
256 | {
257 | return _cnn.GetDatabase().SortedSetRangeByValue(setId, minValue, maxValue, Exclude.Stop).ConvertTo();
258 | });
259 | }
260 |
261 | ///
262 | /// 获取SortedSet长度
263 | ///
264 | ///
265 | ///
266 | public long GetSortedSetLength(string setId)
267 | {
268 | return DoWithRetry(() =>
269 | {
270 | return _cnn.GetDatabase().SortedSetLength(setId);
271 | });
272 | }
273 |
274 | ///
275 | /// 根据值范围儿取SortedSet长度
276 | ///
277 | ///
278 | ///
279 | ///
280 | ///
281 | public long GetSortedSetLength(string setId, double minScore, double maxScore)
282 | {
283 | return DoWithRetry(() =>
284 | {
285 | return _cnn.GetDatabase().SortedSetLength(setId, minScore, maxScore, Exclude.Stop);
286 | });
287 | }
288 |
289 | ///
290 | /// 获取某个SortedSet所在的序号
291 | ///
292 | ///
293 | ///
294 | ///
295 | ///
296 | public long? GetItemRankFromSortedSet(string setId, string item, string order = DefaultOrder)
297 | {
298 | return DoWithRetry(() =>
299 | {
300 | return _cnn.GetDatabase()
301 | .SortedSetRank(setId, item,
302 | order == Order.Descending.ToString().ToLower() ? Order.Descending : Order.Ascending);
303 | });
304 | }
305 |
306 | ///
307 | /// 获取某个SortedSet的score值
308 | ///
309 | ///
310 | ///
311 | ///
312 | public double? GetItemScoreFromSortedSet(string setId, string item)
313 | {
314 | return DoWithRetry(() =>
315 | {
316 | return _cnn.GetDatabase().SortedSetScore(setId, item);
317 | });
318 | }
319 |
320 | ///
321 | /// SortedSet计数器+
322 | ///
323 | ///
324 | ///
325 | ///
326 | ///
327 | public double SetSortedSetItemIncrement(string setId, string item, double score = 1)
328 | {
329 | return DoWithRetry(() =>
330 | {
331 | return _cnn.GetDatabase().SortedSetIncrement(setId, item, score);
332 | });
333 | }
334 |
335 | ///
336 | /// SortedSet计数器-
337 | ///
338 | ///
339 | ///
340 | ///
341 | ///
342 | public double SortedSetItemDecrement(string setId, string item, double score = 1)
343 | {
344 | return DoWithRetry(() =>
345 | {
346 | return _cnn.GetDatabase().SortedSetDecrement(setId, item, score);
347 | });
348 | }
349 |
350 | ///
351 | /// 称除SortedSet
352 | ///
353 | ///
354 | ///
355 | ///
356 | public bool RemoveItemFromSortedSet(string setId, string item)
357 | {
358 | return DoWithRetry(() =>
359 | {
360 | return _cnn.GetDatabase().SortedSetRemove(setId, item);
361 | });
362 | }
363 |
364 | ///
365 | /// 移除某个序号范围的SortedSet
366 | ///
367 | ///
368 | ///
369 | ///
370 | ///
371 | public long RemoveByRankFromSortedSet(string setId, long fromRank, long toRank)
372 | {
373 | return DoWithRetry(() =>
374 | {
375 | return _cnn.GetDatabase().SortedSetRemoveRangeByRank(setId, fromRank, toRank);
376 | });
377 | }
378 |
379 | ///
380 | /// 移除某个score范围的SortedSet
381 | ///
382 | ///
383 | ///
384 | ///
385 | ///
386 | public long RemoveByScoreFromSortedSet(string setId, double minValue, double maxValue)
387 | {
388 | return DoWithRetry(() =>
389 | {
390 | return _cnn.GetDatabase().SortedSetRemoveRangeByScore(setId, minValue, maxValue, Exclude.Stop);
391 | });
392 | }
393 |
394 | #endregion
395 | }
396 | }
397 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisOperationForString.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis.Core
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis.Core
6 | *类 名 称:SERedisOperationForString
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/6/3 15:45:03
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/6/3 15:45:03
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using StackExchange.Redis;
19 | using System;
20 | using System.Collections.Generic;
21 | using System.Threading.Tasks;
22 | using Wenli.Drive.Redis.Interface;
23 | using Wenli.Drive.Redis.Tool;
24 |
25 | namespace Wenli.Drive.Redis.Core
26 | {
27 | ///
28 | /// SERedisOperationForString
29 | ///
30 | public partial class SERedisOperation : IRedisOperation
31 | {
32 |
33 | #region Keys
34 |
35 | ///
36 | /// 是否存在key
37 | ///
38 | ///
39 | ///
40 | public bool KeyExists(string key)
41 | {
42 | return DoWithRetry(() =>
43 | {
44 | return _cnn.GetDatabase().KeyExists(key);
45 | });
46 | }
47 |
48 | ///
49 | /// 设置key过期时间
50 | ///
51 | ///
52 | ///
53 | ///
54 | public bool KeyExpire(string key, DateTime datetime)
55 | {
56 | if (datetime.Kind == DateTimeKind.Unspecified)
57 | {
58 | datetime = DateTime.SpecifyKind(datetime, DateTimeKind.Local);
59 | }
60 | return DoWithRetry(() =>
61 | {
62 | return _cnn.GetDatabase().KeyExpire(key, datetime);
63 | });
64 | }
65 |
66 | ///
67 | /// 设置key过期时间
68 | ///
69 | ///
70 | ///
71 | ///
72 | public bool KeyExpire(string key, int timeout = 0)
73 | {
74 | return DoWithRetry(() =>
75 | {
76 | if (timeout > 0)
77 | return _cnn.GetDatabase().KeyExpire(key, DateTime.Now.AddSeconds(timeout));
78 | return false;
79 | });
80 | }
81 |
82 | ///
83 | /// 设置key
84 | ///
85 | ///
86 | ///
87 | ///
88 | ///
89 | public bool StringSet(string key, string value, int timeout = 0)
90 | {
91 | return DoWithRetry(() =>
92 | {
93 | var bResult = false;
94 | if (timeout > 0)
95 | bResult = _cnn.GetDatabase().StringSet(key, value, new TimeSpan(0, 0, timeout));
96 | else
97 | bResult = _cnn.GetDatabase().StringSet(key, value);
98 | return bResult;
99 | });
100 | }
101 |
102 | ///
103 | /// 设置key
104 | ///
105 | ///
106 | ///
107 | /// key的超时时常
108 | ///
109 | public bool StringSet(string key, string value, TimeSpan expire)
110 | {
111 | return DoWithRetry(() =>
112 | {
113 | return _cnn.GetDatabase().StringSet(key, value, expire);
114 | });
115 | }
116 |
117 | ///
118 | /// 设置一个值,仅在不存在的时候设置
119 | ///
120 | ///
121 | ///
122 | ///
123 | public bool StringSetIfNotExists(string key, string value)
124 | {
125 | return DoWithRetry(() =>
126 | {
127 | return _cnn.GetDatabase().StringSet(key, value, when: When.NotExists);
128 | });
129 | }
130 |
131 | ///
132 | /// 设置一个值,仅在不存在的时候设置
133 | ///
134 | ///
135 | ///
136 | /// 超时时间
137 | ///
138 | public bool StringSetIfNotExists(string key, string value, TimeSpan ts)
139 | {
140 | return DoWithRetry(() =>
141 | {
142 | return _cnn.GetDatabase().StringSet(key, value, ts, when: When.NotExists);
143 | });
144 | }
145 |
146 | ///
147 | /// 获取key的同时set该Key
148 | ///
149 | ///
150 | ///
151 | ///
152 | public string StringGetSet(string key, string value)
153 | {
154 | return DoWithRetry(() =>
155 | {
156 | return _cnn.GetDatabase().StringGetSet(key, value);
157 | });
158 | }
159 |
160 | ///
161 | /// 获取全部keys
162 | ///
163 | ///
164 | ///
165 | [Obsolete("此方法只用于兼容老数据,且本方法只能查询db0,建议使用sortedset来保存keys")]
166 | public List StringGetKeys(string patten = "*")
167 | {
168 | return DoWithRetry(() =>
169 | {
170 | return _cnn.Keys(patten);
171 | });
172 | }
173 |
174 | ///
175 | /// 获取全部keys
176 | ///
177 | ///
178 | ///
179 | ///
180 | ///
181 | [Obsolete("此方法只用于兼容老数据,且本方法只能查询db0,建议使用sortedset来保存keys")]
182 | public void StringGetKeys(Action> callback, string patten = "*", int size = 1000)
183 | {
184 | DoWithRetry(() =>
185 | {
186 | _cnn.Keys(callback, patten, size);
187 | });
188 | }
189 |
190 | ///
191 | /// 获取全部keys
192 | ///
193 | ///
194 | /// ///
195 | ///
196 | ///
197 | [Obsolete("此方法只用于兼容老数据,建议使用sortedset来保存keys")]
198 | public List StringGetKeys(int pageSize, int dbIndex = -1, string patten = "*")
199 | {
200 | return DoWithRetry(() =>
201 | {
202 | List keys = new List();
203 |
204 | var result = _cnn.GetDatabase().ScriptEvaluate(LuaScript.Prepare("return redis.call('KEYS', '*')"), CommandFlags.PreferSlave);
205 |
206 | if (!result.IsNull)
207 | {
208 | var list = (RedisResult[])result;
209 | foreach (var item in list)
210 | {
211 | var key = (RedisKey)item;
212 | keys.Add(key.ToString());
213 | }
214 | }
215 | return keys;
216 | });
217 | }
218 |
219 | ///
220 | /// 获取key
221 | ///
222 | ///
223 | ///
224 | public string StringGet(string key)
225 | {
226 | return DoWithRetry(() =>
227 | {
228 | return _cnn.GetDatabase().StringGet(key);
229 | });
230 | }
231 |
232 | ///
233 | /// 设置key
234 | ///
235 | ///
236 | ///
237 | ///
238 | ///
239 | ///
240 | public bool StringSet(string key, T t, int timeout = 0) where T : class, new()
241 | {
242 | return DoWithRetry(() =>
243 | {
244 | return StringSet(key, SerializeHelper.Serialize(t), timeout);
245 | });
246 | }
247 |
248 | ///
249 | /// 获取key
250 | ///
251 | ///
252 | ///
253 | ///
254 | public T StringGet(string key) where T : class, new()
255 | {
256 | return DoWithRetry(() =>
257 | {
258 | var str = StringGet(key);
259 | if (!string.IsNullOrWhiteSpace(str))
260 | return SerializeHelper.Deserialize(str);
261 | return default(T);
262 | });
263 | }
264 |
265 | ///
266 | /// 批量获取
267 | ///
268 | ///
269 | ///
270 | ///
271 | public List BatchStringGet(List keys) where T : class, new()
272 | {
273 | return DoWithRetry(() =>
274 | {
275 | var batch = _cnn.GetDatabase().CreateBatch();
276 |
277 | List> tasks = new List>();
278 |
279 | foreach (var key in keys)
280 | {
281 | tasks.Add(batch.StringGetAsync(key));
282 | }
283 | batch.Execute();
284 |
285 | List result = new List();
286 |
287 | foreach (var task in tasks)
288 | {
289 | result.Add(SerializeHelper.Deserialize(task.Result));
290 | }
291 |
292 | return result;
293 | });
294 | }
295 |
296 | ///
297 | /// 获取kv列表集合
298 | ///
299 | ///
300 | ///
301 | ///
302 | public List GetValues(List keys) where T : class, new()
303 | {
304 | return DoWithRetry(() =>
305 | {
306 | return GetValues(keys.ToArray());
307 | });
308 | }
309 |
310 | ///
311 | /// 获取kv列表集合
312 | ///
313 | ///
314 | ///
315 | ///
316 | public List GetValues(string[] keys) where T : class, new()
317 | {
318 | return DoWithRetry(() =>
319 | {
320 | var list = new List();
321 | if ((keys != null) && (keys.Length > 0))
322 | foreach (var key in keys)
323 | {
324 | var item = StringGet(key);
325 | if (item != null)
326 | list.Add(item);
327 | }
328 | return list;
329 | });
330 | }
331 |
332 | ///
333 | /// 获取kv列表集合
334 | ///
335 | ///
336 | ///
337 | public List GetValues(string[] keys)
338 | {
339 | return DoWithRetry(() =>
340 | {
341 | var list = new List();
342 | if ((keys != null) && (keys.Length > 0))
343 | foreach (var key in keys)
344 | {
345 | var item = StringGet(key);
346 | if (item != null)
347 | list.Add(item);
348 | }
349 | return list;
350 | });
351 | }
352 |
353 | ///
354 | /// 移除key
355 | ///
356 | ///
357 | ///
358 | public bool KeyDelete(string key)
359 | {
360 | return DoWithRetry(() =>
361 | {
362 | return _cnn.GetDatabase().KeyDelete(key);
363 | });
364 | }
365 |
366 | ///
367 | /// 批量删除
368 | ///
369 | ///
370 | public void KeysDelete(string[] keys)
371 | {
372 | DoWithRetry(() =>
373 | {
374 | for (var i = 0; i < keys.Length; i++)
375 | KeyDelete(keys[i]);
376 | });
377 | }
378 |
379 | ///
380 | /// 批量删除
381 | ///
382 | ///
383 | public void KeysDelete(List keys)
384 | {
385 | DoWithRetry(() =>
386 | {
387 | KeysDelete(keys.ToArray());
388 | });
389 | }
390 |
391 | ///
392 | /// 重命名key
393 | ///
394 | ///
395 | ///
396 | ///
397 | public bool KeyRename(string oldKey, string newKey)
398 | {
399 | return DoWithRetry(() =>
400 | {
401 | return _cnn.GetDatabase().KeyRename(oldKey, newKey);
402 | });
403 | }
404 |
405 | ///
406 | /// key计数器
407 | ///
408 | ///
409 | ///
410 | ///
411 | public double StringIncrement(string key, double value)
412 | {
413 | return DoWithRetry(() =>
414 | {
415 | return _cnn.GetDatabase().StringIncrement(key, value);
416 | });
417 | }
418 |
419 | ///
420 | /// key计数器(减去相应的value)
421 | ///
422 | ///
423 | ///
424 | ///
425 | public double StringDecrement(string key, double value)
426 | {
427 | return DoWithRetry(() =>
428 | {
429 | return _cnn.GetDatabase().StringDecrement(key, value);
430 | });
431 | }
432 |
433 | ///
434 | /// 追加value
435 | ///
436 | ///
437 | ///
438 | ///
439 | public long StringAppend(string key, string value)
440 | {
441 | return DoWithRetry(() =>
442 | {
443 | return _cnn.GetDatabase().StringAppend(value, value, CommandFlags.None);
444 | });
445 | }
446 |
447 | #endregion
448 |
449 | }
450 | }
451 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SERedisOperationForSubPush.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis.Core
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis.Core
6 | *类 名 称:SERedisOperationForSubPush
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/6/3 15:51:48
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/6/3 15:51:48
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using Wenli.Drive.Redis.Interface;
19 | using StackExchange.Redis;
20 | using System;
21 |
22 | namespace Wenli.Drive.Redis.Core
23 | {
24 | ///
25 | /// SERedisOperationForSubPush
26 | ///
27 | public partial class SERedisOperation : IRedisOperation
28 | {
29 | #region SubPush
30 |
31 | private SERedisConnection subcnn;
32 |
33 | ///
34 | /// 订阅消息
35 | ///
36 | ///
37 | ///
38 | public void Subscribe(string channelPrefix, Action action)
39 | {
40 | DoWithRetry(() =>
41 | {
42 | if (subcnn == null)
43 | subcnn = new SERedisConnection(_sectionName, _dbIndex);
44 | var pub = subcnn.GetSubscriber();
45 | pub.Subscribe(new RedisChannel(channelPrefix, RedisChannel.PatternMode.Auto), action);
46 | });
47 | }
48 |
49 | ///
50 | /// 订阅消息
51 | ///
52 | ///
53 | ///
54 | public void SubscribeWithChannel(string channelPrefix, Action action)
55 | {
56 | DoWithRetry(() =>
57 | {
58 | if (subcnn == null)
59 | subcnn = new SERedisConnection(_sectionName, _dbIndex);
60 | var pub = subcnn.GetSubscriber();
61 |
62 | var raction = new Action((c, m) =>
63 | {
64 | action.Invoke(c, m);
65 | });
66 |
67 | pub.Subscribe(new RedisChannel(channelPrefix, RedisChannel.PatternMode.Auto), raction);
68 | });
69 | }
70 |
71 | ///
72 | /// 取消订阅
73 | ///
74 | ///
75 | public void Unsubscribe(string channelPrefix)
76 | {
77 | DoWithRetry(() =>
78 | {
79 | if (subcnn == null)
80 | subcnn = new SERedisConnection(_sectionName, _dbIndex);
81 | var pub = subcnn.GetSubscriber();
82 | pub.Unsubscribe(new RedisChannel(channelPrefix, RedisChannel.PatternMode.Auto));
83 | });
84 | }
85 |
86 | ///
87 | /// 发布消息
88 | ///
89 | ///
90 | ///
91 | public void Publish(string channelPrefix, string msg)
92 | {
93 | DoWithRetry(() =>
94 | {
95 | var pub = _cnn.GetSubscriber();
96 | pub.PublishAsync(new RedisChannel(channelPrefix, RedisChannel.PatternMode.Auto), msg);
97 | });
98 | }
99 |
100 | #endregion
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Core/SESentinelClient.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2016-2020
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:1cc1fa2b-c8c8-4627-bb40-dece98f2b73a
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:Wenli.Drive.Redis
10 | * 命名空间:Wenli.Drive.Redis
11 | * 创建时间:2016/12/28 9:59:30
12 | * 创建人:wenli
13 | * 创建说明:
14 | *****************************************************************************************************/
15 | using System;
16 | using System.Collections.Generic;
17 | using System.Linq;
18 | using System.Net;
19 | using StackExchange.Redis;
20 |
21 | namespace Wenli.Drive.Redis.Core
22 | {
23 | ///
24 | /// SE哨兵操作类
25 | ///
26 | public class SESentinelClient
27 | {
28 | ///
29 | /// 主从切换通知事件委托
30 | ///
31 | ///
32 | ///
33 | ///
34 | public delegate void OnRedisServerChangedHander(string section, string newconnectionString);
35 |
36 | private readonly string _Section = string.Empty;
37 |
38 | private ISubscriber _Sentinelsub;
39 |
40 | private string _password;
41 |
42 | ///
43 | /// 初始化哨兵类
44 | ///
45 | ///
46 | ///
47 | ///
48 | ///
49 | public SESentinelClient(string section, string connectionStr, int poolSize, string password)
50 | {
51 | if (SentinelConnection != null)
52 | SentinelConnection.Dispose();
53 | _Section = section;
54 | SentinelConfig = ConfigurationOptions.Parse(connectionStr);
55 | SentinelConfig.TieBreaker = string.Empty;
56 | SentinelConfig.CommandMap = CommandMap.Sentinel;
57 | PoolSize = poolSize;
58 | _password = password;
59 | }
60 |
61 | ///
62 | /// 哨兵配置
63 | ///
64 | public ConfigurationOptions SentinelConfig
65 | {
66 | get;
67 | }
68 |
69 | ///
70 | /// sentinel连接器
71 | ///
72 | public ConnectionMultiplexer SentinelConnection
73 | {
74 | get; private set;
75 | }
76 |
77 | ///
78 | /// 哨兵对应的节点的池大小
79 | ///
80 | public int PoolSize
81 | {
82 | get;
83 | }
84 |
85 | ///
86 | /// 主从切换通知事件
87 | ///
88 | public event OnRedisServerChangedHander OnRedisServerChanged;
89 |
90 | ///
91 | /// 触发主从切换通知事件
92 | ///
93 | ///
94 | ///
95 | protected void RaiseOnRedisServerChanged(string section, string newconnectionString)
96 | {
97 | if (OnRedisServerChanged != null)
98 | OnRedisServerChanged(section, newconnectionString);
99 | }
100 |
101 | ///
102 | /// 获取活动的哨兵服务器
103 | ///
104 | ///
105 | ///
106 | ///
107 | private IServer GetActiveServer(ConnectionMultiplexer conn, EndPoint[] endpoints)
108 | {
109 | foreach (var endpoint in endpoints)
110 | {
111 | var server = conn.GetServer(endpoint);
112 |
113 | if (server.IsConnected)
114 | return server;
115 | }
116 | throw new Exception("找不到可以连接的活动的哨兵服务器");
117 | }
118 |
119 | ///
120 | /// 中间处理slave endpoint列表
121 | ///
122 | ///
123 | ///
124 | private List SanitizeHostsConfig(KeyValuePair[][] slaves)
125 | {
126 | string ip;
127 | string port;
128 | string flags;
129 |
130 | var servers = new List();
131 | foreach (var slave in slaves)
132 | {
133 | var dic = slave.ToDictionary();
134 |
135 | dic.TryGetValue("flags", out flags);
136 | dic.TryGetValue("ip", out ip);
137 | dic.TryGetValue("port", out port);
138 |
139 | if (ip == "127.0.0.1")
140 | ip = (SentinelConfig.EndPoints.First() as IPEndPoint).Address.ToString();
141 |
142 | if ((ip != null) && (port != null) && !flags.Contains("s_down") && !flags.Contains("o_down"))
143 | servers.Add(string.Format("{0}:{1}", ip, port));
144 | }
145 | return servers;
146 | }
147 |
148 | ///
149 | /// 根据当前哨兵获取对应redis实例的连接字符串
150 | ///
151 | ///
152 | private string GetConnectionStringFromSentinel()
153 | {
154 | try
155 | {
156 | var activeSentinelServer = GetActiveServer(SentinelConnection, SentinelConnection.GetEndPoints());
157 | var masterConnectionInfo = activeSentinelServer.SentinelGetMasterAddressByName(SentinelConfig.ServiceName);
158 | var slaveConnectionInfos =
159 | SanitizeHostsConfig(activeSentinelServer.SentinelSlaves(SentinelConfig.ServiceName));
160 |
161 | var redisConfigs = new ConfigurationOptions
162 | {
163 | AllowAdmin = true,
164 | DefaultDatabase = SentinelConfig.DefaultDatabase,
165 | ConnectRetry = SentinelConfig.ConnectRetry,
166 | ConnectTimeout = SentinelConfig.ConnectTimeout,
167 | KeepAlive = SentinelConfig.KeepAlive,
168 | SyncTimeout = SentinelConfig.SyncTimeout,
169 | AbortOnConnectFail = false
170 | };
171 | if (!string.IsNullOrEmpty(_password))
172 | {
173 | redisConfigs.Password = _password;
174 | }
175 | redisConfigs.EndPoints.Add(masterConnectionInfo);
176 | foreach (var slaveInfo in slaveConnectionInfos)
177 | redisConfigs.EndPoints.Add(slaveInfo);
178 |
179 | return redisConfigs.ToString();
180 | }
181 | catch (Exception ex)
182 | {
183 | throw new Exception(string.Format("SESentinelClient.GetConnectionStringFromSentinel 连接到哨兵服务器({0})失败:{1}", SentinelConfig, ex.Message));
184 | }
185 | }
186 |
187 | ///
188 | /// 连接到指定的Sentinel,获取 master 和 slave 信息并返回。同时,注册相应的事件用于接收 sentinel 的通知消息
189 | ///
190 | ///
191 | public string Start()
192 | {
193 | var redisConnectionString = string.Empty;
194 | try
195 | {
196 | // redis在哨兵模式下,如果Password不为null 或 "",会使用 AUTH 命令,但这个命令是不可用的。
197 | // 所以,克隆一个配置,并将其 Password信息去除
198 | ConfigurationOptions finalSentinalConfig = SentinelConfig;
199 | if (!string.IsNullOrWhiteSpace(SentinelConfig.Password))
200 | {
201 | var cloneConfig = SentinelConfig.Clone();
202 | cloneConfig.Password = "";
203 | finalSentinalConfig = cloneConfig;
204 | }
205 |
206 | SentinelConnection = ConnectionMultiplexer.Connect(finalSentinalConfig);
207 |
208 | redisConnectionString = GetConnectionStringFromSentinel();
209 |
210 | _Sentinelsub = SentinelConnection.GetSubscriber();
211 |
212 | _Sentinelsub.SubscribeAsync("+switch-master", (channle, msg) =>
213 | {
214 | redisConnectionString = GetConnectionStringFromSentinel();
215 | RaiseOnRedisServerChanged(_Section, redisConnectionString);
216 | });
217 | }
218 | catch (Exception ex)
219 | {
220 | throw new Exception(string.Format("SESentinelClient.Start 连接到哨兵服务器({0})失败:{1}", SentinelConfig, ex.Message));
221 | }
222 |
223 | return redisConnectionString;
224 | }
225 | }
226 | }
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Data/PagedDictionary.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis.Data
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis.Data
6 | *类 名 称:PagedDictionary
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/6/30 9:51:39
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/6/30 9:51:39
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Runtime.Serialization;
21 |
22 | namespace Wenli.Drive.Redis.Data
23 | {
24 | ///
25 | /// 分页信息类
26 | ///
27 | [Serializable]
28 | [DataContract]
29 | public class PagedDictionary
30 | {
31 | ///
32 | /// 分页信息类
33 | ///
34 | public PagedDictionary()
35 | {
36 | PageIndex = 1;
37 | PageSize = 20;
38 | Count = 0;
39 | Dictionary = new Dictionary();
40 | }
41 | ///
42 | /// 页号
43 | ///
44 | [DataMember]
45 | public int PageIndex { get; set; }
46 | ///
47 | /// 分页条数
48 | ///
49 | [DataMember]
50 | public int PageSize { get; set; }
51 |
52 | ///
53 | /// 数量
54 | ///
55 | [DataMember]
56 | public long Count { get; set; }
57 |
58 | ///
59 | /// 分页数据内容
60 | ///
61 | [DataMember]
62 | public Dictionary Dictionary { get; set; }
63 |
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Data/PagedList.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2015-2016
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:8c468370-8519-4057-a58e-36fe1ad3ed8a
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:$projectname$
10 | * 命名空间:Wenli.Drive.Redis.Data
11 | * 类名称:PagedList
12 | * 创建时间:2016/12/28 10:02:03
13 | * 创建人:wenli
14 | * 创建说明:
15 | *****************************************************************************************************/
16 | using System;
17 | using System.Collections.Generic;
18 | using System.Runtime.Serialization;
19 |
20 | namespace Wenli.Drive.Redis.Data
21 | {
22 | ///
23 | /// 分页信息类
24 | ///
25 | [Serializable, DataContract]
26 | public class PagedList
27 | {
28 | [DataMember]
29 | public int PageIndex
30 | {
31 | get; set;
32 | }
33 | [DataMember]
34 | public int PageSize
35 | {
36 | get; set;
37 | }
38 | [DataMember]
39 | public long Count
40 | {
41 | get; set;
42 | }
43 | [DataMember]
44 | public List List
45 | {
46 | get; set;
47 | }
48 |
49 | public PagedList()
50 | {
51 | this.PageIndex = 1;
52 | this.PageSize = 20;
53 | this.Count = 0;
54 | this.List = new List();
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Extends/KeyValueConvert.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis.Extends
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis.Extends
6 | *类 名 称:KeyValueConvert
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/6/30 9:50:15
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/6/30 9:50:15
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using StackExchange.Redis;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using Wenli.Drive.Redis.Data;
22 | using Wenli.Drive.Redis.Tool;
23 |
24 | namespace Wenli.Drive.Redis.Extends
25 | {
26 | ///
27 | /// key value 转换
28 | ///
29 | public static class KeyValueConvert
30 | {
31 | ///
32 | /// 转换keys
33 | ///
34 | ///
35 | ///
36 | public static List ConvertTo(this IEnumerable keys)
37 | {
38 | if (keys == null || !keys.Any()) return new List();
39 |
40 | var result = new List();
41 |
42 | foreach (var item in keys)
43 | {
44 | result.Add(item.ToString());
45 | }
46 |
47 | return result;
48 | }
49 |
50 | ///
51 | /// 转换values
52 | ///
53 | ///
54 | ///
55 | public static List ConvertTo(this IEnumerable values)
56 | {
57 | if (values == null || !values.Any()) return new List();
58 |
59 | var result = new List();
60 |
61 | foreach (var item in values)
62 | {
63 | result.Add(item.ToString());
64 | }
65 |
66 | return result;
67 | }
68 |
69 | ///
70 | /// 转换value
71 | ///
72 | ///
73 | ///
74 | ///
75 | public static T ConvertTo(this RedisValue value)
76 | {
77 | if (value.IsNullOrEmpty) return default(T);
78 |
79 | var json = value.ToString();
80 |
81 | return SerializeHelper.Deserialize(json);
82 | }
83 |
84 | ///
85 | /// 转换values
86 | ///
87 | ///
88 | ///
89 | ///
90 | public static List ConvertTo(this IEnumerable values)
91 | {
92 | if (values == null || !values.Any()) return new List();
93 |
94 | var result = new List();
95 |
96 | foreach (var item in values)
97 | {
98 | var json = item.ToString();
99 |
100 | if (!string.IsNullOrEmpty(json))
101 | {
102 | result.Add(SerializeHelper.Deserialize(json));
103 | }
104 | }
105 |
106 | return result;
107 | }
108 |
109 | ///
110 | /// 转换HashEntry
111 | ///
112 | ///
113 | ///
114 | ///
115 | public static Dictionary ConvertTo(this IEnumerable entries)
116 | {
117 | if (entries == null || !entries.Any()) return new Dictionary();
118 |
119 | var result = new Dictionary();
120 |
121 | foreach (var entry in entries)
122 | {
123 | var key = entry.Name.ToString();
124 |
125 | result[key] = entry.Value.ToString();
126 | }
127 |
128 | return result;
129 | }
130 |
131 | ///
132 | /// 转换HashEntry
133 | ///
134 | ///
135 | ///
136 | ///
137 | public static Dictionary ConvertTo(this IEnumerable entries)
138 | {
139 | if (entries == null || !entries.Any()) return new Dictionary();
140 |
141 | var result = new Dictionary();
142 |
143 | foreach (var entry in entries)
144 | {
145 | var key = entry.Name.ToString();
146 |
147 | result[key] = entry.Value.ConvertTo();
148 | }
149 |
150 | return result;
151 | }
152 |
153 | ///
154 | /// 转换SortedSetEntry
155 | ///
156 | ///
157 | ///
158 | public static Dictionary ConvertTo(this IEnumerable entries)
159 | {
160 | if (entries == null || !entries.Any()) return new Dictionary();
161 |
162 | var result = new Dictionary();
163 |
164 | foreach (var entry in entries)
165 | {
166 | var key = entry.Element.ToString();
167 |
168 | result[key] = entry.Score;
169 | }
170 |
171 | return result;
172 | }
173 |
174 | ///
175 | /// 转换SortedSetEntry
176 | ///
177 | ///
178 | ///
179 | ///
180 | ///
181 | ///
182 | public static PagedDictionary ConvertTo(this IEnumerable entries, int pageIndex, int pageSize, long len)
183 | {
184 | if (entries == null || !entries.Any()) return new PagedDictionary();
185 |
186 | var result = new PagedDictionary() { PageIndex = pageIndex, PageSize = pageSize, Count = len };
187 |
188 | var data = new Dictionary();
189 |
190 | foreach (var entry in entries)
191 | {
192 | var key = entry.Element.ToString();
193 |
194 | data[key] = entry.Score;
195 | }
196 |
197 | result.Dictionary = data;
198 |
199 | return result;
200 | }
201 | }
202 | }
203 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Interface/IRedisHelper.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2016-2020
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:1cc1fa2b-c8c8-4627-bb40-dece98f2b73a
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:Wenli.Drive.Redis
10 | * 命名空间:Wenli.Drive.Redis
11 | * 创建时间:2016/12/28 9:59:30
12 | * 创建人:wenli
13 | * 创建说明:
14 | *****************************************************************************************************/
15 | namespace Wenli.Drive.Redis.Interface
16 | {
17 | ///
18 | /// redis操作类实现接口
19 | ///
20 | public interface IRedisHelper
21 | {
22 | ///
23 | /// 初始化池
24 | ///
25 | ///
26 | void Init(string section);
27 |
28 | ///
29 | /// 初始化池
30 | ///
31 | ///
32 | void Init(RedisConfig config);
33 |
34 | ///
35 | /// 初始化池
36 | ///
37 | ///
38 | ///
39 | ///
40 | ///
41 | ///
42 | void Init(string sectionName, RedisConnectType type, string master, string password = "", string serviceName = "");
43 |
44 | ///
45 | /// redis操作
46 | ///
47 | ///
48 | ///
49 | IRedisOperation GetRedisOperation(int dbIndex = -1);
50 | }
51 | }
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/RedisConfig.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2016-2020
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:1cc1fa2b-c8c8-4627-bb40-dece98f2b73a
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:Wenli.Drive.Redis
10 | * 命名空间:Wenli.Drive.Redis
11 | * 创建时间:2016/12/28 9:59:30
12 | * 创建人:wenli
13 | * 创建说明:
14 | *****************************************************************************************************/
15 |
16 | using System.Configuration;
17 |
18 | namespace Wenli.Drive.Redis
19 | {
20 | ///
21 | /// redis配置类
22 | ///
23 | public class RedisConfig : ConfigurationSection
24 | {
25 | ///
26 | /// 当前配置名称
27 | /// 此属性为必须
28 | ///
29 | public string SectionName
30 | {
31 | get; set;
32 | }
33 |
34 | ///
35 | /// 配置类型
36 | ///
37 | [ConfigurationProperty("Type", IsRequired = true)]
38 | public RedisConnectType Type
39 | {
40 | get
41 | {
42 | return (RedisConnectType)base["Type"];
43 | }
44 | set
45 | {
46 | base["Type"] = value;
47 | }
48 | }
49 |
50 | ///
51 | /// 密码
52 | ///
53 | [ConfigurationProperty("Password", IsRequired = false)]
54 | public string Password
55 | {
56 | get
57 | {
58 | return (string)base["Password"];
59 | }
60 | set
61 | {
62 | base["Password"] = value;
63 | }
64 | }
65 |
66 | ///
67 | /// 主Redis库,亦可是sentinel服务器地址
68 | ///
69 | [ConfigurationProperty("Masters", IsRequired = true)]
70 | public string Masters
71 | {
72 | get
73 | {
74 | return (string)base["Masters"];
75 | }
76 | set
77 | {
78 | base["Masters"] = value;
79 | }
80 | }
81 |
82 | ///
83 | /// 从redis库
84 | ///
85 | [ConfigurationProperty("Slaves", IsRequired = false)]
86 | public string Slaves
87 | {
88 | get
89 | {
90 | return (string)base["Slaves"];
91 | }
92 | set
93 | {
94 | base["Slaves"] = value;
95 | }
96 | }
97 |
98 | ///
99 | /// 哨兵模式下服务名称
100 | ///
101 | [ConfigurationProperty("ServiceName", IsRequired = false, DefaultValue = "mymaster")]
102 | public string ServiceName
103 | {
104 | get
105 | {
106 | return (string)base["ServiceName"];
107 | }
108 | set
109 | {
110 | base["ServiceName"] = value;
111 | }
112 | }
113 |
114 | ///
115 | /// 非集群模式下可以指定读写db
116 | ///
117 | [ConfigurationProperty("DefaultDatabase", IsRequired = false, DefaultValue = 0)]
118 | public int DefaultDatabase
119 | {
120 | get
121 | {
122 | return (int)base["DefaultDatabase"];
123 | }
124 | set
125 | {
126 | base["DefaultDatabase"] = value;
127 | }
128 | }
129 |
130 | ///
131 | /// 管理员模式
132 | ///
133 | [ConfigurationProperty("AllowAdmin", IsRequired = false, DefaultValue = true)]
134 | public bool AllowAdmin
135 | {
136 | get
137 | {
138 | return (bool)base["AllowAdmin"];
139 | }
140 | set
141 | {
142 | base["AllowAdmin"] = value;
143 | }
144 | }
145 |
146 | ///
147 | /// 连接保持(s)
148 | ///
149 | [ConfigurationProperty("KeepAlive", IsRequired = false, DefaultValue = 180)]
150 | public int KeepAlive
151 | {
152 | get
153 | {
154 | return (int)base["KeepAlive"];
155 | }
156 | set
157 | {
158 | base["KeepAlive"] = value;
159 | }
160 | }
161 |
162 | ///
163 | /// 连接超时(ms)
164 | ///
165 | [ConfigurationProperty("ConnectTimeout", IsRequired = false, DefaultValue = 10 * 1000)]
166 | public int ConnectTimeout
167 | {
168 | get
169 | {
170 | return (int)base["ConnectTimeout"];
171 | }
172 | set
173 | {
174 | base["ConnectTimeout"] = value;
175 | }
176 | }
177 |
178 | ///
179 | /// 重连次数
180 | ///
181 | [ConfigurationProperty("ConnectRetry", IsRequired = false, DefaultValue = 1)]
182 | public int ConnectRetry
183 | {
184 | get
185 | {
186 | return (int)base["ConnectRetry"];
187 | }
188 | set
189 | {
190 | base["ConnectRetry"] = value;
191 | }
192 | }
193 |
194 | ///
195 | /// 任务忙重试次数
196 | /// 0-10000之间的整数
197 | ///
198 | [ConfigurationProperty("BusyRetry", IsRequired = false, DefaultValue = 10000)]
199 | public int BusyRetry
200 | {
201 | get
202 | {
203 | return (int)base["BusyRetry"];
204 | }
205 | set
206 | {
207 | base["BusyRetry"] = value;
208 | }
209 | }
210 |
211 | ///
212 | /// 重试等待时长(ms)
213 | ///
214 | [ConfigurationProperty("BusyRetryWaitMS", IsRequired = false, DefaultValue = 15000)]
215 | public int BusyRetryWaitMS
216 | {
217 | get
218 | {
219 | return (int)base["BusyRetryWaitMS"];
220 | }
221 | set
222 | {
223 | base["BusyRetryWaitMS"] = value;
224 | }
225 | }
226 |
227 | ///
228 | /// 连接池大小
229 | ///
230 | [ConfigurationProperty("PoolSize", IsRequired = false, DefaultValue = 1)]
231 | public int PoolSize
232 | {
233 | get
234 | {
235 | return (int)base["PoolSize"];
236 | }
237 | set
238 | {
239 | base["PoolSize"] = value;
240 | }
241 | }
242 |
243 |
244 | ///
245 | /// 命令超时时间 (ms)
246 | ///
247 | [ConfigurationProperty("CommandTimeout", IsRequired = false, DefaultValue = 60000)]
248 | public int CommandTimeout
249 | {
250 | get
251 | {
252 | return (int)base["CommandTimeout"];
253 | }
254 | set
255 | {
256 | base["CommandTimeout"] = value;
257 | }
258 | }
259 |
260 | ///
261 | /// 扩展
262 | /// 有一些redis因为禁用了某些命令需要添加如下部分
263 | /// $CLIENT=,$CLUSTER=,$CONFIG=,$ECHO=,$INFO=,$PING=
264 | ///
265 | [ConfigurationProperty("Extention", IsRequired = false, DefaultValue = "")]
266 | public string Extention
267 | {
268 | get
269 | {
270 | return (string)base["Extention"];
271 | }
272 | set
273 | {
274 | base["Extention"] = value;
275 | }
276 | }
277 |
278 | #region 从配置文件中创建redis配置类
279 |
280 | ///
281 | /// 获取默认redis配置类
282 | ///
283 | ///
284 | public static RedisConfig GetConfig()
285 | {
286 | return (RedisConfig)ConfigurationManager.GetSection("RedisConfig");
287 | }
288 |
289 | ///
290 | /// 获取指定的redis配置类
291 | ///
292 | ///
293 | ///
294 | public static RedisConfig GetConfig(string sectionName)
295 | {
296 | var section = (RedisConfig)ConfigurationManager.GetSection(sectionName);
297 | // 跟默认配置相同的,可以省略
298 | if (section == null)
299 | section = GetConfig();
300 | if (section == null)
301 | throw new ConfigurationErrorsException("rediscofig节点 " + sectionName + " 未配置.");
302 | section.SectionName = sectionName;
303 | return section;
304 | }
305 |
306 | ///
307 | /// 从指定位置读取配置
308 | ///
309 | ///
310 | ///
311 | ///
312 | public static RedisConfig GetConfig(string fileName, string sectionName)
313 | {
314 | return GetConfig(ConfigurationManager.OpenMappedMachineConfiguration(new ConfigurationFileMap(fileName)),
315 | sectionName);
316 | }
317 |
318 | ///
319 | /// 从指定Configuration中读取配置
320 | ///
321 | ///
322 | ///
323 | ///
324 | public static RedisConfig GetConfig(Configuration config, string sectionName)
325 | {
326 | if (config == null)
327 | throw new ConfigurationErrorsException("传入的配置不能为空");
328 | var section = (RedisConfig)config.GetSection(sectionName);
329 | if (section == null)
330 | throw new ConfigurationErrorsException("rediscofng节点 " + sectionName + " 未配置.");
331 | section.SectionName = sectionName;
332 | return section;
333 | }
334 |
335 | #endregion
336 | }
337 | }
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/RedisConnectType.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis
6 | *类 名 称:RedisConnectType
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2020/6/30 9:37:49
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2020/6/30 9:37:49
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Text;
21 |
22 | namespace Wenli.Drive.Redis
23 | {
24 | ///
25 | /// redis连接类型
26 | ///
27 | public enum RedisConnectType
28 | {
29 | ///
30 | /// Instance
31 | ///
32 | Instance = 0,
33 | ///
34 | /// Sentinel
35 | ///
36 | Sentinel = 1,
37 | ///
38 | /// Cluster
39 | ///
40 | Cluster = 2
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/RedisHelper.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2016-2020
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:1cc1fa2b-c8c8-4627-bb40-dece98f2b73a
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:Wenli.Drive.Redis
10 | * 命名空间:Wenli.Drive.Redis
11 | * 创建时间:2016/12/28 9:59:30
12 | * 创建人:wenli
13 | * 创建说明:
14 | *****************************************************************************************************/
15 | using System;
16 | using Wenli.Drive.Redis.Interface;
17 | using Wenli.Drive.Redis.Tool;
18 |
19 | namespace Wenli.Drive.Redis
20 | {
21 | ///
22 | /// redis容器类
23 | /// 此类不要直接new(),需要用RedisHelperBuilder来构造
24 | ///
25 | public class RedisHelper
26 | {
27 | private IRedisHelper _redisHelper;
28 |
29 | ///
30 | /// redis容器类
31 | ///
32 | internal RedisHelper() { }
33 |
34 | ///
35 | /// ioc所需初始化方法
36 | ///
37 | ///
38 | internal void CreateInstance(IRedisHelper redisHelper)
39 | {
40 | _redisHelper = redisHelper.DeepCloneForDynamic();
41 | }
42 |
43 | ///
44 | /// 初始化
45 | /// 使用RedisHelperBuilder.Build请不要调用此方法
46 | ///
47 | ///
48 | ///
49 | internal void Init(string sectionName)
50 | {
51 | _redisHelper.Init(sectionName);
52 | }
53 |
54 | ///
55 | /// 自定义初始化
56 | ///
57 | ///
58 | ///
59 | ///
60 | ///
61 | internal void Init(string name, string ipPort, string passwords, RedisConnectType type = RedisConnectType.Instance)
62 | {
63 | _redisHelper.Init(name, type, ipPort, passwords);
64 | }
65 |
66 | ///
67 | /// 初始化
68 | ///
69 | ///
70 | ///
71 | ///
72 | ///
73 | ///
74 | ///
75 | ///
76 | ///
77 | internal void Init(string sectionName, RedisConnectType type, string master, string password = "", string serviceName = "", int poolSize = 1, int busyRetry = 10, int busyRetryWaitMS = 1000)
78 | {
79 | _redisHelper.Init(sectionName, type, master, password, serviceName);
80 | }
81 |
82 | ///
83 | /// 初始化
84 | /// 使用RedisHelperBuilder.Build请不要调用此方法
85 | ///
86 | ///
87 | internal void Init(RedisConfig config)
88 | {
89 | _redisHelper.Init(config);
90 | }
91 |
92 | ///
93 | /// redis操作
94 | ///
95 | ///
96 | ///
97 | public IRedisOperation GetRedisOperation(int dbIndex = -1)
98 | {
99 | return _redisHelper.GetRedisOperation(dbIndex);
100 | }
101 | }
102 | }
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/RedisHelperBuilder.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2016-2020
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:1cc1fa2b-c8c8-4627-bb40-dece98f2b73a
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:Wenli.Drive.Redis
10 | * 命名空间:Wenli.Drive.Redis
11 | * 创建时间:2016/12/28 9:59:30
12 | * 创建人:wenli
13 | * 创建说明:
14 | *****************************************************************************************************/
15 | using System;
16 | using System.Linq;
17 | using System.Reflection;
18 | using Wenli.Drive.Redis.Interface;
19 |
20 | namespace Wenli.Drive.Redis
21 | {
22 | ///
23 | /// RedisClient容器
24 | ///
25 | public static class RedisHelperBuilder
26 | {
27 | private static readonly string _AssemName;
28 |
29 | private static readonly string _TObjectName;
30 |
31 | private static readonly IRedisHelper _instance;
32 |
33 | ///
34 | /// RedisClient容器
35 | ///
36 | static RedisHelperBuilder()
37 | {
38 | var redisClientConfig = "Wenli.Drive.Redis.Core.SERedisHelper;Wenli.Drive.Redis,Version=2.1.0.5,Culture=neutral,PublicKeyToken=null";
39 | var appStrArr = redisClientConfig.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
40 | _TObjectName = appStrArr[0];
41 | _AssemName = appStrArr[1];
42 |
43 | _instance = Assembly.Load(_AssemName).CreateInstance(_TObjectName) as IRedisHelper;
44 | }
45 |
46 | ///
47 | /// 根据指定配置依赖注入产生一个新的实例
48 | ///
49 | ///
50 | /// redis配置实例名称RedisInfo
51 | ///
52 | public static RedisHelper Build(string sectionName)
53 | {
54 | var redisHelper = new RedisHelper();
55 | redisHelper.CreateInstance(_instance);
56 | redisHelper.Init(sectionName);
57 | return redisHelper;
58 | }
59 |
60 | ///
61 | /// 根据指定配置产生一个新的实例
62 | ///
63 | ///
64 | ///
65 | public static RedisHelper Build(RedisConfig config)
66 | {
67 | var redisHelper = new RedisHelper();
68 | redisHelper.CreateInstance(_instance);
69 | redisHelper.Init(config);
70 | return redisHelper;
71 | }
72 |
73 | ///
74 | /// 自定义指定配置连接
75 | ///
76 | /// 这个并非是配置节点名,而是逻辑名
77 | ///
78 | ///
79 | ///
80 | ///
81 | public static RedisHelper Build(string name, string ipPort, string passwords, RedisConnectType type = 0)
82 | {
83 | var redisHelper = new RedisHelper();
84 | redisHelper.CreateInstance(_instance);
85 | redisHelper.Init(name, ipPort, passwords, type);
86 | return redisHelper;
87 | }
88 |
89 | static void Check(params string[] args)
90 | {
91 | if (args == null || !args.Any()) throw new ArgumentNullException("RedisHelperBuilder.Build 必填参数不能空!");
92 |
93 | foreach (var item in args)
94 | {
95 | if (string.IsNullOrEmpty(item))
96 | throw new ArgumentNullException("RedisHelperBuilder.Build 必填参数不能空!");
97 | }
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/RedisLocker.cs:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | *项目名称:Wenli.Drive.Redis
3 | *CLR 版本:4.0.30319.42000
4 | *机器名称:WALLE-PC
5 | *命名空间:Wenli.Drive.Redis
6 | *类 名 称:RedisLocker
7 | *版 本 号:V1.0.0.0
8 | *创建人: yswenli
9 | *电子邮箱:yswenli@outlook.com
10 | *创建时间:2019/10/18 9:38:07
11 | *描述:
12 | *=====================================================================
13 | *修改时间:2019/10/18 9:38:07
14 | *修 改 人: yswenli
15 | *版 本 号: V1.0.0.0
16 | *描 述:
17 | *****************************************************************************/
18 | using System;
19 |
20 | namespace Wenli.Drive.Redis
21 | {
22 | ///
23 | /// 分布式锁,
24 | /// using(RedisLocker)
25 | ///
26 | public class RedisLocker : IDisposable
27 | {
28 | RedisHelper _redisHelper = null;
29 |
30 | ///
31 | /// 分布式锁
32 | ///
33 | ///
34 | ///
35 | ///
36 | ///
37 | public RedisLocker(RedisConfig redisConfig, string key, int timeout = 30 * 1000, int rolling = 50)
38 | {
39 | _redisHelper = RedisHelperBuilder.Build(redisConfig);
40 |
41 | if (!_redisHelper.GetRedisOperation().Lock(key, timeout, rolling))
42 | {
43 | throw new Exception("RedisLocker申请锁已超时!");
44 | }
45 | }
46 |
47 | ///
48 | /// 分布式锁
49 | ///
50 | ///
51 | ///
52 | ///
53 | ///
54 | ///
55 | ///
56 | ///
57 | public RedisLocker(string serviceName, string ipPort, string passwords, RedisConnectType type, string key, int timeout = 30 * 1000, int rolling = 50)
58 | {
59 | _redisHelper = RedisHelperBuilder.Build(serviceName, ipPort, passwords, type);
60 |
61 | if (!_redisHelper.GetRedisOperation().Lock(key, timeout, rolling))
62 | {
63 | throw new Exception("RedisLocker申请锁已超时!");
64 | }
65 | }
66 |
67 | ///
68 | /// dispose
69 | ///
70 | public void Dispose()
71 | {
72 | _redisHelper.GetRedisOperation().UnLock();
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Tool/SerializeHelper.cs:
--------------------------------------------------------------------------------
1 | /*****************************************************************************************************
2 | * 本代码版权归@wenli所有,All Rights Reserved (C) 2015-2016
3 | *****************************************************************************************************
4 | * CLR版本:4.0.30319.42000
5 | * 唯一标识:c52026f9-2b01-46ec-a21d-76ab1d34270f
6 | * 机器名称:WENLI-PC
7 | * 联系人邮箱:wenguoli_520@qq.com
8 | *****************************************************************************************************
9 | * 项目名称:$projectname$
10 | * 命名空间:Wenli.Drive.Redis.Tool
11 | * 类名称:SerializeHelper
12 | * 创建时间:2016/12/28 9:56:53
13 | * 创建人:wenli
14 | * 创建说明:
15 | *****************************************************************************************************/
16 | using System;
17 | using System.IO;
18 | using System.Runtime.Serialization.Formatters.Binary;
19 | using Newtonsoft.Json;
20 |
21 | namespace Wenli.Drive.Redis.Tool
22 | {
23 | ///
24 | /// 序列化类
25 | ///
26 | public static class SerializeHelper
27 | {
28 | ///
29 | /// newton.json序列化,日志参数专用
30 | ///
31 | ///
32 | ///
33 | public static string Serialize(object obj)
34 | {
35 | JsonSerializerSettings jsetting = new JsonSerializerSettings();
36 | jsetting.ObjectCreationHandling = ObjectCreationHandling.Replace;
37 | jsetting.DateFormatString = "yyyy-MM-dd HH:mm:ss.fff";
38 | return JsonConvert.SerializeObject(obj, jsetting);
39 | }
40 |
41 | ///
42 | /// newton.json反序列化,日志参数专用
43 | ///
44 | ///
45 | ///
46 | ///
47 | public static T Deserialize(string json)
48 | {
49 | JsonSerializerSettings jsetting = new JsonSerializerSettings();
50 | jsetting.ObjectCreationHandling = ObjectCreationHandling.Replace;
51 | jsetting.DateFormatString = "yyyy-MM-dd HH:mm:ss.fff";
52 | return JsonConvert.DeserializeObject(json, jsetting);
53 | }
54 |
55 | ///
56 | /// newton.json反序列化
57 | ///
58 | ///
59 | /// 反序列化的类型
60 | ///
61 | public static object Deserialize(string json, Type type)
62 | {
63 | JsonSerializerSettings settings = new JsonSerializerSettings();
64 | settings.ObjectCreationHandling = ObjectCreationHandling.Replace;
65 | settings.DateFormatString = "yyyy-MM-dd HH:mm:ss.fff";
66 | return JsonConvert.DeserializeObject(json, type, settings);
67 | }
68 |
69 | ///
70 | /// 二进制序列化
71 | ///
72 | ///
73 | ///
74 | public static byte[] ByteSerialize(object obj)
75 | {
76 |
77 | using (MemoryStream m = new MemoryStream())
78 | {
79 |
80 | BinaryFormatter bin = new BinaryFormatter();
81 | bin.Serialize(m, obj);
82 |
83 | return m.ToArray();
84 |
85 | }
86 |
87 | }
88 |
89 | ///
90 | /// 二进制反序列化
91 | ///
92 | ///
93 | ///
94 | ///
95 | public static T ByteDeserialize(byte[] buffer)
96 | {
97 |
98 | using (MemoryStream m = new MemoryStream())
99 | {
100 |
101 | m.Write(buffer, 0, buffer.Length);
102 | m.Position = 0;
103 |
104 | BinaryFormatter bin = new BinaryFormatter();
105 |
106 | return (T)bin.Deserialize(m);
107 |
108 | }
109 |
110 | }
111 |
112 | ///
113 | /// 深复制当前对象
114 | ///
115 | ///
116 | ///
117 | ///
118 | public static dynamic DeepCloneForDynamic(this T obj)
119 | {
120 | var json = Serialize(obj);
121 | return Deserialize(json, obj.GetType());
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/Wenli.Drive.Redis.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | 2.2.8.8
6 | This is a.Net redis integrated driver to support a single instance, cluster, sentinel and other modes of data manipulation 这是一个.net 的redis集成驱动,支持单实例、云集群、哨兵等模式的数据操作
7 | Wenli.Drive.Redis @ yswenli
8 | Wenli.Drive.Redis,Redis,RedisCluster,RedisSentinel
9 | true
10 | true
11 | https://raw.githubusercontent.com/yswenli/RedisDrive/master/LICENSE
12 | This is a.Net redis integrated driver to support a single instance, cluster, sentinel and other modes of data manipulation 这是一个.net 的redis集成驱动,支持单实例、云集群、哨兵等模式的数据操作
13 | https://github.com/yswenli/RedisDrive
14 | http://www.cnblogs.com/yswenli/p/6235765.html
15 | 2.2.8.8
16 | 2.2.8.8
17 |
18 |
19 |
20 | x64
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Wenli.Drive.Redis/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/wenli.drive.redis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yswenli/RedisDrive/ed8f81d5bb8d56a11567b8d3f7d360b90ceb1bc6/wenli.drive.redis.png
--------------------------------------------------------------------------------