173 lines
6.1 KiB
C#
173 lines
6.1 KiB
C#
using FreeRedis;
|
||
using Masuit.Tools;
|
||
using Newtonsoft.Json;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace YuanXuan.IM.Infrastructure.Redis
|
||
{
|
||
public abstract class RedisHelper
|
||
{
|
||
|
||
private static RedisClient _instance;
|
||
|
||
/// <summary>
|
||
/// redis实例
|
||
/// </summary>
|
||
public static RedisClient Instance
|
||
{
|
||
get
|
||
{
|
||
if (_instance == null)
|
||
{
|
||
throw new Exception("使用前初始化redis静态访问类 RedisHelper.Initialization(new FreeRedis.RedisClient(\"127.0.0.1:6379,password=123,defaultDatabase=13,maxpoolsize=50,prefix=key前辍\"));");
|
||
}
|
||
|
||
return _instance;
|
||
}
|
||
}
|
||
public static void SetLoginToken(long userId, string token)
|
||
{
|
||
var key = "Login_Token";
|
||
Instance.HSet(key, userId.ToString(), token);
|
||
}
|
||
public static void DeleteLoginToken(long userId)
|
||
{
|
||
var key = "Login_Token";
|
||
Instance.HDel(key, userId.ToString());
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 初始化redis静态访问类 RedisHelper.Initialization(new FreeRedis.RedisClient(\"127.0.0.1:6379,password=123,defaultDatabase=13,maxpoolsize=50,prefix=key前辍\"))
|
||
/// </summary>
|
||
/// <param name="redisClient"></param>
|
||
public static void Initialization(string connectionString)
|
||
{
|
||
_instance = new FreeRedis.RedisClient(connectionString)
|
||
{
|
||
Serialize = (x) => x.ToJsonString(),
|
||
Deserialize = (x, t) => JsonConvert.DeserializeObject(x, t),
|
||
};
|
||
}
|
||
|
||
internal static ThreadLocal<Random> rnd = new ThreadLocal<Random>(() => new Random());
|
||
/// <summary>
|
||
/// 随机秒(防止所有key同一时间过期,雪崩)
|
||
/// </summary>
|
||
/// <param name="minTimeoutSeconds">最小秒数</param>
|
||
/// <param name="maxTimeoutSeconds">最大秒数</param>
|
||
/// <returns></returns>
|
||
public static int RandomExpired(int minTimeoutSeconds, int maxTimeoutSeconds) => rnd.Value.Next(minTimeoutSeconds, maxTimeoutSeconds);
|
||
/// <summary>
|
||
/// 获取Redis分布式锁
|
||
/// </summary>
|
||
/// <param name="lockKey">锁键</param>
|
||
/// <param name="lockValue">锁值(建议使用GUID)</param>
|
||
/// <param name="expireSeconds">过期时间(秒)</param>
|
||
/// <returns>是否获取成功</returns>
|
||
public static bool TryLock(string lockKey, string lockValue, int expireSeconds = 30)
|
||
{
|
||
return Instance.SetNx(lockKey, lockValue, expireSeconds);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 释放Redis分布式锁
|
||
/// </summary>
|
||
/// <param name="lockKey">锁键</param>
|
||
/// <param name="lockValue">锁值(必须与加锁时一致)</param>
|
||
/// <returns>是否释放成功</returns>
|
||
public static bool ReleaseLock(string lockKey, string lockValue)
|
||
{
|
||
// 使用Lua脚本确保原子性:只有当锁的值匹配时才删除
|
||
const string luaScript = @"
|
||
if redis.call('GET', KEYS[1]) == ARGV[1] then
|
||
return redis.call('DEL', KEYS[1])
|
||
else
|
||
return 0
|
||
end";
|
||
|
||
var result = Instance.Eval(luaScript, new[] { lockKey }, new[] { lockValue });
|
||
return (long)result == 1;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 延长Redis锁的过期时间
|
||
/// </summary>
|
||
/// <param name="lockKey">锁键</param>
|
||
/// <param name="lockValue">锁值</param>
|
||
/// <param name="expireSeconds">新的过期时间(秒)</param>
|
||
/// <returns>是否续期成功</returns>
|
||
public static bool RenewLock(string lockKey, string lockValue, int expireSeconds)
|
||
{
|
||
// 使用Lua脚本确保原子性:只有当锁的值匹配时才更新过期时间
|
||
const string luaScript = @"
|
||
if redis.call('GET', KEYS[1]) == ARGV[1] then
|
||
return redis.call('EXPIRE', KEYS[1], ARGV[2])
|
||
else
|
||
return 0
|
||
end";
|
||
|
||
var result = Instance.Eval(luaScript, new[] { lockKey }, new[] { lockValue, expireSeconds.ToString() });
|
||
return (long)result == 1;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步设置键值对
|
||
/// </summary>
|
||
/// <param name="key">键</param>
|
||
/// <param name="value">值</param>
|
||
/// <param name="expiry">过期时间</param>
|
||
/// <returns></returns>
|
||
public static async Task SetAsync(string key, object value, TimeSpan expiry)
|
||
{
|
||
await Instance.SetAsync(key, value, expiry);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步获取字符串值
|
||
/// </summary>
|
||
/// <param name="key">键</param>
|
||
/// <returns></returns>
|
||
public static async Task<string> GetStringAsync(string key)
|
||
{
|
||
return await Instance.GetAsync<string>(key);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步删除键
|
||
/// </summary>
|
||
/// <param name="key">键</param>
|
||
/// <returns></returns>
|
||
public static async Task DeleteAsync(string key)
|
||
{
|
||
await Instance.DelAsync(key);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步获取值
|
||
/// </summary>
|
||
/// <typeparam name="T">类型</typeparam>
|
||
/// <param name="key">键</param>
|
||
/// <returns></returns>
|
||
public static async Task<T> GetAsync<T>(string key)
|
||
{
|
||
return await Instance.GetAsync<T>(key);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步设置键值对(默认过期时间)
|
||
/// </summary>
|
||
/// <param name="key">键</param>
|
||
/// <param name="value">值</param>
|
||
/// <returns></returns>
|
||
public static async Task SetAsync(string key, object value)
|
||
{
|
||
await Instance.SetAsync(key, value);
|
||
}
|
||
}
|
||
}
|