using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using MrWu.Debug;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using StackExchange.Redis;
namespace Server.DB.Redis {
public static class RedisCachingHelper {
///
/// 默认缓存过期时间,单位:秒
///
public static int ExpireBySecond { get; set; } = 3600;// 86400;
/*
*
* 主要用法 GetOrAdd
* RedisType 参数表示 Redis 存储类型,当前支持,String/Hash/List
* 泛型类型支持
* String 全部JSON支持的类型
* Hash 除简单类型外,所有有无参构造方法的类型, 注意:实现IDictionary的类型只支持IDictionary成员,不支持继承扩展属性/字段;
* List 数组 以及 实现 IList 接口类型有无参构造的类型;
*
* acquire Redis 未命中时获取对象的委托方法, 必须返回一个有效对象,以避免缓存穿透
* key Redis 标识关键字
* dbIdx Redis Database Id
* throwIfKeyTypeWrong 在从Redis获取对象时 Redis Key类型错误或对象成员类型错误时是否抛异常, 无此参数的重载默认为 true。
* 注意:所有操作redis的网络异常将被屏蔽,所有由类型不匹配和不支持类型将会抛 ArgumentOutOfRangeException 异常
*
* 缓存过期时间指定,可以使用有expire参数的重载以固定值指定,也可以使用 acquire 参数类型为 Func> 的重载以灵活方式指定
*
* 其他:使用本扩展方法,将会对象及对象成员的类型保持强类型特性,存储在redis上的数据是经过JSON格式包装,修改数据必须注意格式。
**/
#region 扩展方法
#region GetOrAdd Generic Sync
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func acquire) {
return dbStyle.GetOrAdd(redisType, key, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func acquire, int dbIdx) {
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func acquire, TimeSpan expire) {
return dbStyle.GetOrAdd(redisType, key, acquire, -1, expire, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(redisType, key, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func acquire, int dbIdx, int expireBySecond) {
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func acquire, int dbIdx, TimeSpan expire) {
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, expire, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func acquire, int dbIdx, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func acquire, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func acquire, TimeSpan expire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(redisType, key, acquire, -1, expire, throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func acquire, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = acquire();
db.AddToRedis(redisType, key, value, expire);
return value;
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire) {
return dbStyle.GetOrAdd(redisType, key, acquire, -1, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, int dbIdx) {
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(redisType, key, acquire, -1, throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = acquire();
db.AddToRedis(redisType, key, value.Item1, TimeSpan.FromSeconds(value.Item2));
return value.Item1;
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire) {
return dbStyle.GetOrAdd(redisType, key, acquire, -1, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, int dbIdx) {
return dbStyle.GetOrAdd(redisType, key, acquire, dbIdx, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(redisType, key, acquire, -1, throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = acquire();
db.AddToRedis(redisType, key, value.Item1, value.Item2);
return value.Item1;
}
#endregion
#region GetOrAdd Generic Async
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, int dbIdx) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, TimeSpan expire) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, expire, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, int dbIdx, int expireBySecond) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, int dbIdx, TimeSpan expire) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, expire, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, TimeSpan expire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, expire, throwIfKeyTypeWrong);
}
public static async Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func> acquire, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = await acquire.Invoke();
db.AddToRedis(redisType, key, value, expire);
return value;
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func>> acquire) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func>> acquire, int dbIdx) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func>> acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, throwIfKeyTypeWrong);
}
public static async Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = await acquire();
db.AddToRedis(redisType, key, value.Item1, TimeSpan.FromSeconds(value.Item2));
return value.Item1;
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func>> acquire) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func>> acquire, int dbIdx) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, dbIdx, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func>> acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAddAsync(redisType, key, acquire, -1, throwIfKeyTypeWrong);
}
public static async Task GetOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, Func>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(redisType, key, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = await acquire();
db.AddToRedis(redisType, key, value.Item1, value.Item2);
return value.Item1;
}
#endregion
#region GetOrAdd RedisHash Sync
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func acquire) {
return dbStyle.GetOrAdd(key, field, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func acquire, int dbIdx) {
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func acquire, TimeSpan expire) {
return dbStyle.GetOrAdd(key, field, acquire, -1, expire, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(key, field, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func acquire, int dbIdx, int expireBySecond) {
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func acquire, int dbIdx, TimeSpan expire) {
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, expire, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func acquire, int dbIdx, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func acquire, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func acquire, TimeSpan expire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(key, field, acquire, -1, expire, throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func acquire, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = acquire();
db.AddToRedis(key, field, keyExists, value, expire);
return value;
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire) {
return dbStyle.GetOrAdd(key, field, acquire, -1, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, int dbIdx) {
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(key, field, acquire, -1, throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = acquire();
db.AddToRedis(key, field, keyExists, value.Item1, TimeSpan.FromSeconds(value.Item2));
return value.Item1;
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire) {
return dbStyle.GetOrAdd(key, field, acquire, -1, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, int dbIdx) {
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, true);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(key, field, acquire, -1, throwIfKeyTypeWrong);
}
public static T GetOrAdd(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = acquire();
db.AddToRedis(key, field, keyExists, value.Item1, value.Item2);
return value.Item1;
}
public static bool TryGet(this IDatabase db, RedisKey key, RedisValue field, out bool keyExists, out T outValue, bool throwIfKeyTypeWrong) {
outValue = default(T);
keyExists = false;
try {
var transaction = db.CreateTransaction();
var task1 = transaction.KeyTimeToLiveAsync(key);
var task2 = transaction.HashGetAsync(key, field);
if (transaction.Execute()) {
var task1Result = task1.Result;
keyExists = task1Result.HasValue && task1Result.Value > TimeSpan.Zero;
var redisValue = task2.Result;
if (!keyExists || redisValue.IsNullOrEmpty) {
return false;
}
return GetObjectFromJsonWrapper(redisValue, out outValue, throwIfKeyTypeWrong, true, throwIfKeyTypeWrong);
}
} catch (Exception ex) {
Console.WriteLine(ex);
}
return false;
}
public static bool AddToRedis(this IDatabase db, RedisKey key, RedisValue field, bool keyExists, object value, TimeSpan timeSpan) {
try {
var transaction = db.CreateTransaction();
transaction.HashSetAsync(key, field, GetStringOfJsonWrapper(value));
if (!keyExists) {
transaction.KeyExpireAsync(key, timeSpan);
}
return transaction.Execute();
} catch (Exception ex) {
Console.WriteLine(ex);
}
return false;
}
#endregion
#region GetOrAdd RedisHash Async
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire) {
return dbStyle.GetOrAddAsync(key, field, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, int dbIdx) {
return dbStyle.GetOrAddAsync(key, field, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, TimeSpan expire) {
return dbStyle.GetOrAddAsync(key, field, acquire, -1, expire, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAddAsync(key, field, acquire, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, int dbIdx, int expireBySecond) {
return dbStyle.GetOrAddAsync(key, field, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, int dbIdx, TimeSpan expire) {
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, expire, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAddAsync(key, field, acquire, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAdd(key, field, acquire, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, TimeSpan expire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAddAsync(key, field, acquire, -1, expire, throwIfKeyTypeWrong);
}
public static async Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func> acquire, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = await acquire();
db.AddToRedis(key, field, keyExists, value, expire);
return value;
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func>> acquire) {
return dbStyle.GetOrAddAsync(key, field, acquire, -1, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func>> acquire, int dbIdx) {
return dbStyle.GetOrAddAsync(key, field, acquire, dbIdx, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func>> acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAddAsync(key, field, acquire, -1, throwIfKeyTypeWrong);
}
public static async Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = await acquire();
db.AddToRedis(key, field, keyExists, value.Item1, TimeSpan.FromSeconds(value.Item2));
return value.Item1;
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func>> acquire) {
return dbStyle.GetOrAddAsync(key, field, acquire, -1, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func>> acquire, int dbIdx) {
return dbStyle.GetOrAddAsync(key, field, acquire, dbIdx, true);
}
public static Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func>> acquire, bool throwIfKeyTypeWrong) {
return dbStyle.GetOrAddAsync(key, field, acquire, -1, throwIfKeyTypeWrong);
}
public static async Task GetOrAddAsync(this DbStyle dbStyle, RedisKey key, RedisValue field, Func>> acquire, int dbIdx, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
if (db.TryGet(key, field, out var keyExists, out var outValue, throwIfKeyTypeWrong)) {
return outValue;
}
var value = await acquire();
db.AddToRedis(key, field, keyExists, value.Item1, value.Item2);
return value.Item1;
}
#endregion
#region UpdateOrAdd
public static T UpdateOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value) {
return dbStyle.UpdateOrAdd(redisType, key, value, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static T UpdateOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx) {
return dbStyle.UpdateOrAdd(redisType, key, value, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static T UpdateOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
return dbStyle.UpdateOrAdd(redisType, key, value, -1, expire, true);
}
public static T UpdateOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, bool throwIfKeyTypeWrong) {
return dbStyle.UpdateOrAdd(redisType, key, value, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static T UpdateOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, int expireBySecond) {
return dbStyle.UpdateOrAdd(redisType, key, value, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
}
public static T UpdateOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, TimeSpan expire) {
return dbStyle.UpdateOrAdd(redisType, key, value, dbIdx, expire, true);
}
public static T UpdateOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, bool throwIfKeyTypeWrong) {
return dbStyle.UpdateOrAdd(redisType, key, value, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static T UpdateOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
return dbStyle.UpdateOrAdd(redisType, key, value, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
}
public static T UpdateOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire, bool throwIfKeyTypeWrong) {
return dbStyle.UpdateOrAdd(redisType, key, value, -1, expire, throwIfKeyTypeWrong);
}
public static T UpdateOrAdd(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
var existRedisKeyType = RedisType.None;
try {
//获取原有数据类型
existRedisKeyType = db.KeyType(key);
} catch (Exception ex) {
Debug.Error($"RedisCachingHelper UpdateOrAdd db.KeyType fail, key: {key}, ex: {ex}");
}
//检查原有key数据类型
if (existRedisKeyType != RedisType.None && existRedisKeyType != redisType && throwIfKeyTypeWrong) {
throw new ArgumentOutOfRangeException($"redis key 当前存储的数据类型为:{existRedisKeyType}, 新类型为:{redisType}");
}
db.AddToRedis(redisType, key, value, expire);
return value;
}
#endregion
#region UpdateOrAdd Async
public static Task UpdateOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value) {
return dbStyle.UpdateOrAddAsync(redisType, key, value, -1, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static Task UpdateOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx) {
return dbStyle.UpdateOrAddAsync(redisType, key, value, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), true);
}
public static Task UpdateOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
return dbStyle.UpdateOrAddAsync(redisType, key, value, -1, expire, true);
}
public static Task UpdateOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, bool throwIfKeyTypeWrong) {
return dbStyle.UpdateOrAddAsync(redisType, key, value, -1, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static Task UpdateOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, int expireBySecond) {
return dbStyle.UpdateOrAddAsync(redisType, key, value, dbIdx, TimeSpan.FromSeconds(expireBySecond), true);
}
public static Task UpdateOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, TimeSpan expire) {
return dbStyle.UpdateOrAddAsync(redisType, key, value, dbIdx, expire, true);
}
public static Task UpdateOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, bool throwIfKeyTypeWrong) {
return dbStyle.UpdateOrAddAsync(redisType, key, value, dbIdx, TimeSpan.FromSeconds(ExpireBySecond), throwIfKeyTypeWrong);
}
public static Task UpdateOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, int expireBySecond, bool throwIfKeyTypeWrong) {
return dbStyle.UpdateOrAddAsync(redisType, key, value, dbIdx, TimeSpan.FromSeconds(expireBySecond), throwIfKeyTypeWrong);
}
public static Task UpdateOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire, bool throwIfKeyTypeWrong) {
return dbStyle.UpdateOrAddAsync(redisType, key, value, -1, expire, throwIfKeyTypeWrong);
}
public static async Task UpdateOrAddAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int dbIdx, TimeSpan expire, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
var existRedisKeyType = RedisType.None;
try {
//获取原有数据类型
existRedisKeyType = await db.KeyTypeAsync(key);
} catch (Exception ex) {
Debug.Error($"RedisCachingHelper UpdateOrAdd db.KeyType fail, key: {key}, ex: {ex}");
}
//检查原有key数据类型
if (existRedisKeyType != RedisType.None && existRedisKeyType != redisType && throwIfKeyTypeWrong) {
throw new ArgumentOutOfRangeException($"redis key 当前存储的数据类型为:{existRedisKeyType}, 新类型为:{redisType}");
}
db.AddToRedis(redisType, key, value, expire);
return value;
}
#endregion
#region Delete
public static bool Delete(this DbStyle dbStyle, int dbIdx = -1, params RedisKey[] keys) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
return db.KeyDelete(keys) == keys.Length;
}
public static async Task DeleteAsync(this DbStyle dbStyle, int dbIdx = -1, params RedisKey[] keys) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
var count = await db.KeyDeleteAsync(keys);
return count == keys.Length;
}
public static IDatabase GetDataBase(this DbStyle dbStyle, int dbIdx) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
return db;
}
#endregion
#region TryGet
public static bool TryGet(this DbStyle dbStyle, RedisType redisType, RedisKey key, out T outValue) {
return dbStyle.TryGet(redisType, key, out outValue, -1, true);
}
public static bool TryGet(this DbStyle dbStyle, RedisType redisType, RedisKey key, out T outValue, int dbIdx) {
return dbStyle.TryGet(redisType, key, out outValue, dbIdx, true);
}
public static bool TryGet(this DbStyle dbStyle, RedisType redisType, RedisKey key, out T outValue, bool throwIfKeyTypeWrong) {
return dbStyle.TryGet(redisType, key, out outValue, -1, throwIfKeyTypeWrong);
}
public static bool TryGet(this DbStyle dbStyle, RedisType redisType, RedisKey key, out T outValue, int dbIdx, bool throwIfKeyTypeWrong) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
return db.TryGet(redisType, key, out outValue, throwIfKeyTypeWrong);
}
public static bool TryGet(this IDatabase db, RedisType redisType, RedisKey key, out T outValue, bool throwIfKeyTypeWrong) {
EnsureKeyNotEmptyOrNULL(key);
switch (redisType) {
case RedisType.String:
return db.TryGetString(key, out outValue, throwIfKeyTypeWrong);
case RedisType.Hash:
return db.TryGetHash(key, out outValue, throwIfKeyTypeWrong);
case RedisType.List:
return db.TryGetList(key, out outValue, throwIfKeyTypeWrong);
case RedisType.Set:
case RedisType.SortedSet:
throw new NotSupportedException(); //return db.TryGetSet(key, out outValue, throwIfKeyTypeWrong);
case RedisType.None:
//case RedisType.Stream:
case RedisType.Unknown:
default:
throw new NotSupportedException($"key: {key}, redisType: {redisType}");
}
}
#endregion
#region AddToRedis
public static bool AddToRedis(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value) {
return dbStyle.AddToRedis(redisType, key, value, TimeSpan.FromSeconds(ExpireBySecond), -1);
}
public static bool AddToRedis(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int expire) {
return dbStyle.AddToRedis(redisType, key, value, TimeSpan.FromSeconds(expire), -1);
}
public static bool AddToRedis(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int expire, int dbIdx) {
return dbStyle.AddToRedis(redisType, key, value, TimeSpan.FromSeconds(expire), dbIdx);
}
public static bool AddToRedis(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
return dbStyle.AddToRedis(redisType, key, value, expire, -1);
}
public static bool AddToRedis(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire, int dbIdx) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
return db.AddToRedis(redisType, key, value, expire);
}
public static bool AddToRedis(this IDatabase db, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
EnsureKeyNotEmptyOrNULL(key);
switch (redisType) {
case RedisType.String:
return db.AddStringToRedis(key, value, expire);
case RedisType.Hash:
return db.AddHashToRedis(key, value, expire);
case RedisType.List:
return db.AddListToRedis(key, value as IEnumerable, expire);
case RedisType.Set:
case RedisType.SortedSet:
throw new NotSupportedException(); //return db.AddSetToRedis(key, value, expire);
case RedisType.None:
//case RedisType.Stream:
case RedisType.Unknown:
default:
throw new NotSupportedException($"key: {key}, redisType: {redisType}");
}
}
#endregion
#region AddToRedis Async
public static Task AddToRedisAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value) {
return dbStyle.AddToRedisAsync(redisType, key, value, TimeSpan.FromSeconds(ExpireBySecond), -1);
}
public static Task AddToRedisAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int expire) {
return dbStyle.AddToRedisAsync(redisType, key, value, TimeSpan.FromSeconds(expire), -1);
}
public static Task AddToRedisAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, int expire, int dbIdx) {
return dbStyle.AddToRedisAsync(redisType, key, value, TimeSpan.FromSeconds(expire), dbIdx);
}
public static Task AddToRedisAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
return dbStyle.AddToRedisAsync(redisType, key, value, expire, -1);
}
public static Task AddToRedisAsync(this DbStyle dbStyle, RedisType redisType, RedisKey key, T value, TimeSpan expire, int dbIdx) {
var db = redisManager.GetDataBase(dbStyle, dbIdx);
return db.AddToRedisAsync(redisType, key, value, expire);
}
public static Task AddToRedisAsync(this IDatabase db, RedisType redisType, RedisKey key, T value, TimeSpan expire) {
EnsureKeyNotEmptyOrNULL(key);
switch (redisType) {
case RedisType.String:
return db.AddStringToRedisAsync(key, value, expire);
case RedisType.Hash:
return db.AddHashToRedisAsync(key, value, expire);
case RedisType.List:
return db.AddListToRedisAsync(key, value as IEnumerable, expire);
case RedisType.Set:
case RedisType.SortedSet:
throw new NotSupportedException(); //return db.AddSetToRedis(key, value, expire);
case RedisType.None:
//case RedisType.Stream:
case RedisType.Unknown:
default:
throw new NotSupportedException($"key: {key}, redisType: {redisType}");
}
}
#endregion
public static IDatabase GetRedisDataBase(this DbStyle style, int dbIdx = -1) => redisManager.GetDataBase(style, dbIdx);
#endregion
#region 扩展功能实现
#region 以 Redis String 类型存储
static bool TryGetString(this IDatabase db, RedisKey key, out T outValue, bool throwIfKeyTypeWrong) {
outValue = default(T);
if (!db.GetFromRedis(key, throwIfKeyTypeWrong, p => p.StringGet(key), out var redisValue)) {
return false;
}
//检查原始类型与目标类型是否一致
return !redisValue.IsNullOrEmpty && GetObjectFromJsonWrapper(redisValue, out outValue, throwIfKeyTypeWrong, true, throwIfKeyTypeWrong);
}
static bool AddStringToRedis(this IDatabase db, RedisKey key, T value, TimeSpan expire) {
var stringValue = GetStringOfJsonWrapper(value);
return db.ExecuctRedisTransaction(key, expire, false, transaction => transaction.StringSetAsync(key, stringValue));
}
static Task AddStringToRedisAsync(this IDatabase db, RedisKey key, T value, TimeSpan expire) {
var stringValue = GetStringOfJsonWrapper(value);
return db.ExecuctRedisTransactionAsync(key, expire, false, transaction => transaction.StringSetAsync(key, stringValue));
}
#endregion
#region 以 Redis Hash 类型存储
public readonly static string hash_type_field_name = "_@_type_@_name_@_";
static bool TryGetHash(this IDatabase db, RedisKey key, out T outValue, bool throwIfKeyTypeWrong) {
outValue = default(T);
if (!db.GetFromRedis(key, throwIfKeyTypeWrong, p => p.HashGetAll(key), out var hashEntries)) {
return false;
}
if (hashEntries.Length == 0) {
return false;
}
var targetType = typeof(T);
var item = hashEntries.SingleOrDefault(p => hash_type_field_name.Equals(p.Name)).Value;
if (item.IsNullOrEmpty) {
if (throwIfKeyTypeWrong) {
throw new ArgumentOutOfRangeException($"Hash 原始类型描述为空:目标类型:{ targetType.FullName}");
}
return false;
}
Type originType = null;
try {
originType = Type.GetType(item);
} catch (Exception ex) {
Debug.Error($"TryGetHash Type.GetType fail, type: {item}, ex: {ex}");
}
if (originType == null) {
if (throwIfKeyTypeWrong) {
throw new ArgumentOutOfRangeException($"无法获取原始类型:{originType}");
}
return false;
}
hashEntries = hashEntries.Where(p => !string.Equals(p.Name, hash_type_field_name)).ToArray();
//检查原始类型与目标类型是否一致
if (!originType.Equals(targetType)) {
if (throwIfKeyTypeWrong) {
throw new ArgumentOutOfRangeException($"无效的目标类型:原始类型:{originType.FullName}, 目标类型:{targetType.FullName}");
}
return false;
}
outValue = Activator.CreateInstance();
var dictionaryGeneric = targetType.GetInterface(typeOfIDictionaryGeneric.Name);
if (dictionaryGeneric != null) {
//目标类型是 IDictionary<,>
var genericArgs = dictionaryGeneric.GetGenericArguments();
var method = TryGetIDictionaryGenericMethod.MakeGenericMethod(genericArgs);
var succ = (bool)method.Invoke(null, new object[] { outValue, hashEntries });
if (!succ) {
if (throwIfKeyTypeWrong) {
throw new ArgumentOutOfRangeException($"TryGetHash 解释元素类型不未成功!");
}
}
return succ;
} else if (outValue is IDictionary dictionary) {
//目标类型是 IDictionary
return LoadDictionaryMembersFromHashEntries(hashEntries, dictionary, targetType, throwIfKeyTypeWrong);
} else {
//目标类型是非 IDictionary 类型
return LoadObjectMembersFromHashEntries(hashEntries, outValue, targetType, throwIfKeyTypeWrong);
}
}
static readonly Type typeOfRedisCachingHelper = typeof(RedisCachingHelper);
static Type typeOfObject { get; } = typeof(object);
static Type typeOfCollectionGeneric { get; } = typeof(Collection<>);
static Type typeOfIListGeneric { get; } = typeof(IList<>);
static Type typeOfIList { get; } = typeof(IList);
static Type typeOfIDictionaryGeneric { get; } = typeof(IDictionary<,>);
static bool LoadDictionaryMembersFromHashEntries(HashEntry[] hashEntries, IDictionary dictionary, Type targetType, bool throwIfKeyTypeWrong) {
foreach (var item in hashEntries) {
if (!item.Name.IsNullOrEmpty) {
try {
if (GetObjectFromJsonWrapper(item.Name, out var dictionaryKeyname) && GetObjectFromJsonWrapper(item.Value, out var dictValue)) {
dictionary.Add(dictionaryKeyname, dictValue);
}
} catch (Exception ex) {
Debug.Error($"StaticCachingHelper LoadDictionaryMembersFromHashEntries fail, ex: {ex}");
if (throwIfKeyTypeWrong) {
throw new ArgumentOutOfRangeException($"解析数据发生异常,目标类型:{targetType.FullName}!", ex);
}
return false;
}
} else {
if (throwIfKeyTypeWrong) {
throw new ArgumentOutOfRangeException($"无效的原始成员名称, Name:{item.Name}, Value:{targetType.FullName}");
}
return false;
}
}
return true;
}
static bool LoadObjectMembersFromHashEntries(HashEntry[] hashEntries, object instance, Type targetType, bool throwIfKeyTypeWrong) {
var fields = targetType.GetFields(BindingFlags.Public | BindingFlags.Instance).Where(p => !p.IsInitOnly).ToArray();
var props = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0).ToArray();
if (fields.Length == 0 && props.Length == 0) {
if (throwIfKeyTypeWrong) {
throw new ArgumentOutOfRangeException($"类型:{targetType} 没有公开的可读写字段或属性");
}
return false;
}
foreach (var item in hashEntries) {
if (!item.Value.IsNullOrEmpty) {
Action