1、StackExchange的安装可以参考:
https://www.cnblogs.com/cang12138/p/8884362.html
https://www.cnblogs.com/liqingwen/p/6672452.html
https://www.cnblogs.com/wangyulong/p/8656215.html
2、我自己参考写的封装
(1)redis.cs
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
namespace YChain.SinDouGame.Services
{
public class Redis : ICache
{
int Default_Timeout = 7 * 24 * 60 * 60;//默认超时时间(单位秒)
string address;
JsonSerializerSettings jsonConfig = new JsonSerializerSettings() { ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore, NullValueHandling = NullValueHandling.Ignore };
ConnectionMultiplexer connectionMultiplexer;
IDatabase database;
string DefaultKey { get; set; }
[Serializable]
class CacheObject<T>
{
public int ExpireTime { get; set; }
public bool ForceOutofDate { get; set; }
public T Value { get; set; }
}
public Redis()
{
this.address = ConfigurationManager.AppSettings["RedisServer"] ?? "127.0.0.1:6379";
if (this.address == null || string.IsNullOrWhiteSpace(this.address.ToString()))
throw new ApplicationException("配置文件中未找到RedisServer的有效配置");
connectionMultiplexer = ConnectionMultiplexer.Connect(address);
database = connectionMultiplexer.GetDatabase();
DefaultKey = ConfigurationManager.AppSettings["Redis.DefaultKey"] ?? "DefaultKey";
}
/// <summary>
/// 连接超时设置
/// </summary>
public int TimeOut
{
get
{
return Default_Timeout;
}
set
{
Default_Timeout = value;
}
}
public object Get(string key)
{
return Get<object>(key);
}
public T Get<T>(string key)
{
try
{
DateTime begin = DateTime.Now;
var cacheValue = database.StringGet(key);
DateTime endCache = DateTime.Now;
var value = default(T);
if (!cacheValue.IsNull)
{
//var cacheObject = Deserialize<CacheObject<T>>(cacheValue);
//if (!cacheObject.ForceOutofDate)
// database.KeyExpire(key, new TimeSpan(0, 0, cacheObject.ExpireTime));
//value = cacheObject.Value;
var cacheObject = Deserialize<T>(cacheValue);
value = cacheObject;
}
DateTime endJson = DateTime.Now;
return value;
}
catch (Exception ex)
{
Log.writelog("Redis.Get", ex.Message, "redis.txt");
database.KeyDelete(key, CommandFlags.HighPriority);
return default(T);
}
}
public void Insert(string key, string data)
{
database.StringSet(key, data);
}
public string GetString(string key)
{
return (string)database.StringGet(key);
}
public void Insert(string key, object data)
{
var jsonData = GetJsonData(data, TimeOut, false);
database.StringSet(key, jsonData);
}
public void Insert(string key, object data, int cacheTime)
{
var timeSpan = TimeSpan.FromSeconds(cacheTime);
var jsonData = GetJsonData(data, TimeOut, true);
database.StringSet(key, jsonData, timeSpan);
}
public void Insert(string key, object data, DateTime cacheTime)
{
var timeSpan = cacheTime - DateTime.Now;
var jsonData = GetJsonData(data, TimeOut, true);
database.StringSet(key, jsonData, timeSpan);
}
public bool Insert<T>(string key, T data)
{
var jsonData = GetJsonData<T>(data, TimeOut, false);
return database.StringSet(key, jsonData);
}
public void Insert<T>(string key, T data, int cacheTime)
{
var timeSpan = TimeSpan.FromSeconds(cacheTime);
var jsonData = GetJsonData<T>(data, TimeOut, true);
database.StringSet(key, jsonData, timeSpan);
}
public void Insert<T>(string key, T data, DateTime cacheTime)
{
var timeSpan = cacheTime - DateTime.Now;
var jsonData = GetJsonData<T>(data, TimeOut, true);
database.StringSet(key, jsonData, timeSpan);
}
public long StringIncrement(string key)
{
return database.StringIncrement(key);
}
byte[] GetJsonData(object data, int cacheTime, bool forceOutOfDate)
{
//var cacheObject = new CacheObject<object>() { Value = data, ExpireTime = cacheTime, ForceOutofDate = forceOutOfDate };
//return Serialize(cacheObject);//序列化对象
return Serialize(data);//序列化对象
}
byte[] GetJsonData<T>(T data, int cacheTime, bool forceOutOfDate)
{
//var cacheObject = new CacheObject<T>() { Value = data, ExpireTime = cacheTime, ForceOutofDate = forceOutOfDate };
//return Serialize(cacheObject);//序列化对象
return Serialize(data);//序列化对象
}
/// <summary>
/// 删除
/// </summary>
/// <param name="key"></param>
public void Remove(string key)
{
database.KeyDelete(key, CommandFlags.HighPriority);
}
/// <summary>
/// 判断key是否存在
/// </summary>
public bool Exists(string key)
{
return database.KeyExists(key);
}
#region List 操作
/// <summary>
/// 添加 Key 的前缀
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private static string AddKeyPrefix(string key)
{
return key;
}
/// <summary>
/// 移除并返回存储在该键列表的第一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public string ListLeftPop(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return database.ListLeftPop(redisKey);
}
/// <summary>
/// 移除并返回存储在该键列表的最后一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public string ListRightPop(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return database.ListRightPop(redisKey);
}
/// <summary>
/// 移除列表指定键上与该值相同的元素
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public long ListRemove(string redisKey, string redisValue)
{
redisKey = AddKeyPrefix(redisKey);
return database.ListRemove(redisKey, redisValue);
}
/// <summary>
/// 在列表尾部插入值。如果键不存在,先创建再插入值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public long ListRightPush(string redisKey, string redisValue)
{
redisKey = AddKeyPrefix(redisKey);
return database.ListRightPush(redisKey, redisValue);
}
/// <summary>
/// 在列表头部插入值。如果键不存在,先创建再插入值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public long ListLeftPush(string redisKey, string redisValue)
{
redisKey = AddKeyPrefix(redisKey);
return database.ListLeftPush(redisKey, redisValue);
}
/// <summary>
/// 返回列表上该键的长度,如果不存在,返回 0
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public long ListLength(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return database.ListLength(redisKey);
}
/// <summary>
/// 返回在该列表上键所对应的元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public IEnumerable<RedisValue> ListRange(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return database.ListRange(redisKey);
}
/// <summary>
/// 移除并返回存储在该键列表的第一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public T ListLeftPop<T>(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(database.ListLeftPop(redisKey));
}
/// <summary>
/// 移除并返回存储在该键列表的最后一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public T ListRightPop<T>(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(database.ListRightPop(redisKey));
}
/// <summary>
/// 在列表尾部插入值。如果键不存在,先创建再插入值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public long ListRightPush<T>(string redisKey, T redisValue)
{
redisKey = AddKeyPrefix(redisKey);
return database.ListRightPush(redisKey, Serialize(redisValue));
}
/// <summary>
/// 在列表头部插入值。如果键不存在,先创建再插入值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public long ListLeftPush<T>(string redisKey, T redisValue)
{
redisKey = AddKeyPrefix(redisKey);
return database.ListLeftPush(redisKey, Serialize(redisValue));
}
/// <summary>
///
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public string ListGetByIndex(string redisKey, long index)
{
redisKey = AddKeyPrefix(redisKey);
return database.ListGetByIndex(redisKey, index);
}
#region List-async
/// <summary>
/// 移除并返回存储在该键列表的第一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<string> ListLeftPopAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await database.ListLeftPopAsync(redisKey);
}
/// <summary>
/// 移除并返回存储在该键列表的最后一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<string> ListRightPopAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await database.ListRightPopAsync(redisKey);
}
/// <summary>
/// 移除列表指定键上与该值相同的元素
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public async Task<long> ListRemoveAsync(string redisKey, string redisValue)
{
redisKey = AddKeyPrefix(redisKey);
return await database.ListRemoveAsync(redisKey, redisValue);
}
/// <summary>
/// 在列表尾部插入值。如果键不存在,先创建再插入值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public async Task<long> ListRightPushAsync(string redisKey, string redisValue)
{
redisKey = AddKeyPrefix(redisKey);
return await database.ListRightPushAsync(redisKey, redisValue);
}
/// <summary>
/// 在列表头部插入值。如果键不存在,先创建再插入值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public async Task<long> ListLeftPushAsync(string redisKey, string redisValue)
{
redisKey = AddKeyPrefix(redisKey);
return await database.ListLeftPushAsync(redisKey, redisValue);
}
/// <summary>
/// 返回列表上该键的长度,如果不存在,返回 0
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<long> ListLengthAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await database.ListLengthAsync(redisKey);
}
/// <summary>
/// 返回在该列表上键所对应的元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<IEnumerable<RedisValue>> ListRangeAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await database.ListRangeAsync(redisKey);
}
/// <summary>
/// 移除并返回存储在该键列表的第一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<T> ListLeftPopAsync<T>(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(await database.ListLeftPopAsync(redisKey));
}
/// <summary>
/// 移除并返回存储在该键列表的最后一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<T> ListRightPopAsync<T>(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(await database.ListRightPopAsync(redisKey));
}
/// <summary>
/// 在列表尾部插入值。如果键不存在,先创建再插入值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public async Task<long> ListRightPushAsync<T>(string redisKey, T redisValue)
{
redisKey = AddKeyPrefix(redisKey);
return await database.ListRightPushAsync(redisKey, Serialize(redisValue));
}
/// <summary>
/// 在列表头部插入值。如果键不存在,先创建再插入值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public async Task<long> ListLeftPushAsync<T>(string redisKey, T redisValue)
{
redisKey = AddKeyPrefix(redisKey);
return await database.ListLeftPushAsync(redisKey, Serialize(redisValue));
}
#endregion List-async
#endregion List 操作
#region Hash 操作
/// <summary>
/// 判断该字段是否存在 hash 中
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public bool HashExists(string redisKey, string hashField)
{
redisKey = AddKeyPrefix(redisKey);
return database.HashExists(redisKey, hashField);
}
/// <summary>
/// 从 hash 中移除指定字段
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public bool HashDelete(string redisKey, string hashField)
{
redisKey = AddKeyPrefix(redisKey);
return database.HashDelete(redisKey, hashField);
}
/// <summary>
/// 从 hash 中移除指定字段
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public long HashDelete(string redisKey, IEnumerable<RedisValue> hashField)
{
redisKey = AddKeyPrefix(redisKey);
return database.HashDelete(redisKey, hashField.ToArray());
}
/// <summary>
/// 在 hash 设定值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool HashSet(string redisKey, string hashField, string value)
{
redisKey = AddKeyPrefix(redisKey);
return database.HashSet(redisKey, hashField, value);
}
/// <summary>
/// 在 hash 设定值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool HashSet(string redisKey, string hashField, long value)
{
redisKey = AddKeyPrefix(redisKey);
return database.HashSet(redisKey, hashField, value);
}
/// <summary>
/// 在 hash 中设定值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashFields"></param>
public void HashSet(string redisKey, IEnumerable<HashEntry> hashFields)
{
redisKey = AddKeyPrefix(redisKey);
database.HashSet(redisKey, hashFields.ToArray());
}
/// <summary>
/// 在 hash 中获取值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public object HashGet(string redisKey, string hashField)
{
redisKey = AddKeyPrefix(redisKey);
return database.HashGet(redisKey, hashField);
}
/// <summary>
/// 在 hash 中获取值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <param name="value"></param>
/// <returns></returns>
public RedisValue[] HashGet(string redisKey, RedisValue[] hashField, string value)
{
redisKey = AddKeyPrefix(redisKey);
return database.HashGet(redisKey, hashField);
}
/// <summary>
/// 从 hash 返回所有的字段值
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public IEnumerable<RedisValue> HashKeys(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return database.HashKeys(redisKey);
}
/// <summary>
/// 返回 hash 中的所有值
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public RedisValue[] HashValues(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return database.HashValues(redisKey);
}
/// <summary>
/// 在 hash 设定值(序列化)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool HashSet<T>(string redisKey, string hashField, T value)
{
redisKey = AddKeyPrefix(redisKey);
var json = YChain.Framework.Core.Serializers.JsonSerializer.Serialize(value);
return database.HashSet(redisKey, hashField, json);
//RedisValue obj = getobj(value);
//return database.HashSet(redisKey, hashField, obj);
}
public long SortedSetLength(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return database.SortedSetLength(redisKey);
}
public bool SortedSetAdd<T>(string redisKey, T member, double score)
{
redisKey = AddKeyPrefix(redisKey);
var json = YChain.Framework.Core.Serializers.JsonSerializer.Serialize(member);
return database.SortedSetAdd(redisKey, json, score, CommandFlags.None);
}
public bool SortedSetRemove<T>(string redisKey, T member)
{
redisKey = AddKeyPrefix(redisKey);
var json = YChain.Framework.Core.Serializers.JsonSerializer.Serialize(member);
return database.SortedSetRemove(redisKey, json);
}
public List<T> SortedSetRangeByScore<T>(string redisKey, double start, double stop)
{
redisKey = AddKeyPrefix(redisKey);
var hashVals = database.SortedSetRangeByScore(redisKey, start, stop, Exclude.None, Order.Descending);
List<T> list = new List<T>();
foreach (var item in hashVals)
{
list.Add(YChain.Framework.Core.Serializers.JsonSerializer.Deserialize<T>(item.ToString()));
}
return list;
}
public List<T> SortedSetRangeByRank<T>(string redisKey, long start, long stop)
{
redisKey = AddKeyPrefix(redisKey);
var hashVals = database.SortedSetRangeByRank(redisKey, start, stop, Order.Descending);
List<T> list = new List<T>();
foreach (var item in hashVals)
{
list.Add(YChain.Framework.Core.Serializers.JsonSerializer.Deserialize<T>(item.ToString()));
}
return list;
}
public RedisValue getobj(object value)
{
return (RedisValue)value;
}
public object getobj(RedisValue value)
{
return value;
}
/// <summary>
/// 在 hash 中获取值(反序列化)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public T HashGet<T>(string redisKey, string hashField)
{
try
{
redisKey = AddKeyPrefix(redisKey);
var t = database.HashGet(redisKey, hashField);
string str = t.ToString();
return YChain.Framework.Core.Serializers.JsonSerializer.Deserialize<T>(str);
}
catch(Exception ex)
{
return default(T);
}
//return Deserialize<T>(database.HashGet(redisKey, hashField));
//RedisValue obj = database.HashGet(redisKey, hashField);
//return (T)getobj(obj);
}
/// <summary>
/// 在 hash 中获取值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public string HashGetString(string redisKey, string hashField)
{
try
{
redisKey = AddKeyPrefix(redisKey);
var t = database.HashGet(redisKey, hashField);
string str = t.ToString();
return str;
}
catch (Exception ex)
{
return null;
}
}
/// <summary>
/// 一个有问题的迭代器,可以便利hash key的全部元素
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="pattern"></param>
/// <param name="pageSize"></param>
/// <returns></returns>
public List<T> HashScan<T>(string key, int pageSize, int pageOffset)
{
List<T> list = new List<T>();
var hashVals = database.HashScan(key, pageSize, 0, pageOffset).ToList();
foreach (var item in hashVals)
{
list.Add(YChain.Framework.Core.Serializers.JsonSerializer.Deserialize<T>(item.Value));
}
return list;
}
#region async
/// <summary>
/// 判断该字段是否存在 hash 中
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public async Task<bool> HashExistsAsync(string redisKey, string hashField)
{
redisKey = AddKeyPrefix(redisKey);
return await database.HashExistsAsync(redisKey, hashField);
}
/// <summary>
/// 从 hash 中移除指定字段
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public async Task<bool> HashDeleteAsync(string redisKey, string hashField)
{
redisKey = AddKeyPrefix(redisKey);
return await database.HashDeleteAsync(redisKey, hashField);
}
/// <summary>
/// 从 hash 中移除指定字段
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public async Task<long> HashDeleteAsync(string redisKey, IEnumerable<RedisValue> hashField)
{
redisKey = AddKeyPrefix(redisKey);
return await database.HashDeleteAsync(redisKey, hashField.ToArray());
}
/// <summary>
/// 在 hash 设定值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <param name="value"></param>
/// <returns></returns>
public async Task<bool> HashSetAsync(string redisKey, string hashField, string value)
{
redisKey = AddKeyPrefix(redisKey);
return await database.HashSetAsync(redisKey, hashField, value);
}
/// <summary>
/// 在 hash 中设定值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashFields"></param>
public async Task HashSetAsync(string redisKey, IEnumerable<HashEntry> hashFields)
{
redisKey = AddKeyPrefix(redisKey);
await database.HashSetAsync(redisKey, hashFields.ToArray());
}
/// <summary>
/// 在 hash 中获取值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public async Task<RedisValue> HashGetAsync(string redisKey, string hashField)
{
redisKey = AddKeyPrefix(redisKey);
return await database.HashGetAsync(redisKey, hashField);
}
/// <summary>
/// 在 hash 中获取值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <param name="value"></param>
/// <returns></returns>
public async Task<IEnumerable<RedisValue>> HashGetAsync(string redisKey, RedisValue[] hashField, string value)
{
redisKey = AddKeyPrefix(redisKey);
return await database.HashGetAsync(redisKey, hashField);
}
/// <summary>
/// 从 hash 返回所有的字段值
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<IEnumerable<RedisValue>> HashKeysAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await database.HashKeysAsync(redisKey);
}
/// <summary>
/// 返回 hash 中的所有值
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<IEnumerable<RedisValue>> HashValuesAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await database.HashValuesAsync(redisKey);
}
/// <summary>
/// 在 hash 设定值(序列化)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <param name="value"></param>
/// <returns></returns>
public async Task<bool> HashSetAsync<T>(string redisKey, string hashField, T value)
{
redisKey = AddKeyPrefix(redisKey);
var json = Serialize(value);
return await database.HashSetAsync(redisKey, hashField, json);
}
/// <summary>
/// 在 hash 中获取值(反序列化)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public async Task<T> HashGetAsync<T>(string redisKey, string hashField)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(await database.HashGetAsync(redisKey, hashField));
}
#endregion async
#endregion Hash 操作
/// <summary>
/// 序列化
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
private static byte[] Serialize(object obj)
{
if (obj == null)
return null;
var binaryFormatter = new BinaryFormatter();
using (var memoryStream = new MemoryStream())
{
binaryFormatter.Serialize(memoryStream, obj);
var data = memoryStream.ToArray();
return data;
}
}
/// <summary>
/// 反序列化
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
private static T Deserialize<T>(byte[] data)
{
if (data == null)
return default(T);
var binaryFormatter = new BinaryFormatter();
using (var memoryStream = new MemoryStream(data))
{
var result = (T)binaryFormatter.Deserialize(memoryStream);
return result;
}
}
public bool LockTake(string redisKey, string redisValue, TimeSpan timeSpan)
{
return database.LockTake(redisKey, redisValue, timeSpan);
}
public bool LockRelease(string redisKey, string redisValue)
{
return database.LockRelease(redisKey, redisValue);
}
}
}
(2)ICache.cs
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YChain.SinDouGame.Services
{
public interface ICache
{
/// <summary>
/// 缓存过期时间
/// </summary>
int TimeOut { set; get; }
/// <summary>
/// 获得指定键的缓存值
/// </summary>
/// <param name="key">缓存键</param>
/// <returns>缓存值</returns>
object Get(string key);
/// <summary>
/// 获得指定键的缓存值
/// </summary>
T Get<T>(string key);
/// <summary>
/// 从缓存中移除指定键的缓存值
/// </summary>
/// <param name="key">缓存键</param>
void Remove(string key);
/// <summary>
/// 清空所有缓存对象
/// </summary>
//void Clear();
/// <summary>
/// 将指定键的对象添加到缓存中
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
void Insert(string key, object data);
/// <summary>
/// 将指定键的对象添加到缓存中
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
bool Insert<T>(string key, T data);
/// <summary>
/// 将指定键的对象添加到缓存中,并指定过期时间
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
/// <param name="cacheTime">缓存过期时间(秒钟)</param>
void Insert(string key, object data, int cacheTime);
/// <summary>
/// 将指定键的对象添加到缓存中,并指定过期时间
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
/// <param name="cacheTime">缓存过期时间(秒钟)</param>
void Insert<T>(string key, T data, int cacheTime);
/// <summary>
/// 将指定键的对象添加到缓存中,并指定过期时间
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
/// <param name="cacheTime">缓存过期时间</param>
void Insert(string key, object data, DateTime cacheTime);
/// <summary>
/// 将指定键的对象添加到缓存中,并指定过期时间
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
/// <param name="cacheTime">缓存过期时间</param>
void Insert<T>(string key, T data, DateTime cacheTime);
/// <summary>
/// 判断key是否存在
/// </summary>
bool Exists(string key);
/// <summary>
/// 值自加1
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
long StringIncrement(string key);
long ListLeftPush(string redisKey, string redisValue);
long ListRightPush(string redisKey, string redisValue);
string ListRightPop(string redisKey);
string ListLeftPop(string redisKey);
T ListLeftPop<T>(string redisKey);
T ListRightPop<T>(string redisKey);
long ListRightPush<T>(string redisKey, T redisValue);
long ListLeftPush<T>(string redisKey, T redisValue);
long ListLength(string redisKey);
string ListGetByIndex(string redisKey, long index);
bool LockTake(string redisKey, string redisValue, TimeSpan cacheTime);
bool LockRelease(string redisKey, string redisValue);
void Insert(string key, string data);
string GetString(string key);
#region Hash 操作
bool HashExists(string redisKey, string hashField);
bool HashDelete(string redisKey, string hashField);
bool HashSet(string redisKey, string hashField, string value);
bool HashSet(string redisKey, string hashField, long value);
bool HashSet<T>(string redisKey, string hashField, T value);
T HashGet<T>(string redisKey, string hashField);
string HashGetString(string redisKey, string hashField);
object HashGet(string redisKey, string hashField);
List<T> HashScan<T>(string key, int pageSize, int pageOffset);
#endregion Hash 操作
long SortedSetLength(string redisKey);
bool SortedSetAdd<T>(string redisKey, T member, double score);
bool SortedSetRemove<T>(string redisKey, T member);
List<T> SortedSetRangeByScore<T>(string redisKey, double start, double stop);
List<T> SortedSetRangeByRank<T>(string redisKey, long start, long stop);
}
}
(3) RedisCache.cs
using StackExchange.Redis;
using System;
using System.Collections.Generic;
namespace YChain.SinDouGame.Services
{
/// <summary>
/// 缓存
/// </summary>
public static class RedisCache
{
private static object cacheLocker = new object();//缓存锁对象
private static ICache cache = null;//缓存接口
static RedisCache()
{
Load();
}
/// <summary>
/// 加载缓存
/// </summary>
/// <exception cref=""></exception>
private static void Load()
{
try
{
cache = new Redis();
}
catch (Exception ex)
{
//Log.Error(ex.Message);
}
}
public static ICache GetCache()
{
return cache;
}
/// <summary>
/// 缓存过期时间
/// </summary>
public static int TimeOut
{
get
{
return cache.TimeOut;
}
set
{
lock (cacheLocker)
{
cache.TimeOut = value;
}
}
}
public static void Insert(string key, string data)
{
cache.Insert(key, data);
}
public static string GetString(string key)
{
return cache.GetString(key);
}
/// <summary>
/// 获得指定键的缓存值
/// </summary>
/// <param name="key">缓存键</param>
/// <returns>缓存值</returns>
public static object Get(string key)
{
if (string.IsNullOrWhiteSpace(key))
return null;
return cache.Get(key);
}
/// <summary>
/// 获得指定键的缓存值
/// </summary>
/// <param name="key">缓存键</param>
/// <returns>缓存值</returns>
public static T Get<T>(string key)
{
return cache.Get<T>(key);
}
/// <summary>
/// 将指定键的对象添加到缓存中
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
public static void Insert(string key, object data)
{
if (string.IsNullOrWhiteSpace(key) || data == null)
return;
//lock (cacheLocker)
{
cache.Insert(key, data);
}
}
/// <summary>
/// 将指定键的对象添加到缓存中
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
public static bool Insert<T>(string key, T data)
{
if (string.IsNullOrWhiteSpace(key) || data == null)
return false;
//lock (cacheLocker)
{
return cache.Insert<T>(key, data);
}
}
/// <summary>
/// 将指定键的对象添加到缓存中,并指定过期时间
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
/// <param name="cacheTime">缓存过期时间(分钟)</param>
public static void Insert(string key, object data, int cacheTime)
{
if (!string.IsNullOrWhiteSpace(key) && data != null)
{
//lock (cacheLocker)
{
cache.Insert(key, data, cacheTime);
}
}
}
/// <summary>
/// 将指定键的对象添加到缓存中,并指定过期时间
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
/// <param name="cacheTime">缓存过期时间(分钟)</param>
public static void Insert<T>(string key, T data, int cacheTime)
{
if (!string.IsNullOrWhiteSpace(key) && data != null)
{
//lock (cacheLocker)
{
cache.Insert<T>(key, data, cacheTime);
}
}
}
/// <summary>
/// 将指定键的对象添加到缓存中,并指定过期时间
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
/// <param name="cacheTime">缓存过期时间</param>
public static void Insert(string key, object data, DateTime cacheTime)
{
if (!string.IsNullOrWhiteSpace(key) && data != null)
{
//lock (cacheLocker)
{
cache.Insert(key, data, cacheTime);
}
}
}
/// <summary>
/// 将指定键的对象添加到缓存中,并指定过期时间
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="data">缓存值</param>
/// <param name="cacheTime">缓存过期时间</param>
public static void Insert<T>(string key, T data, DateTime cacheTime)
{
if (!string.IsNullOrWhiteSpace(key) && data != null)
{
//lock (cacheLocker)
{
cache.Insert<T>(key, data, cacheTime);
}
}
}
/// <summary>
/// 从缓存中移除指定键的缓存值
/// </summary>
/// <param name="key">缓存键</param>
public static void Remove(string key)
{
if (string.IsNullOrWhiteSpace(key))
return;
lock (cacheLocker)
{
cache.Remove(key);
}
}
/// <summary>
/// 判断key是否存在
/// </summary>
public static bool Exists(string key)
{
return cache.Exists(key);
}
/// <summary>
/// 值自加1
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static long StringIncrement(string key)
{
return cache.StringIncrement(key);
}
public static long ListLeftPush(string redisKey, string redisValue)
{
return cache.ListLeftPush(redisKey, redisValue);
}
public static long ListRightPush(string redisKey, string redisValue)
{
return cache.ListRightPush(redisKey, redisValue);
}
public static string ListRightPop(string redisKey)
{
return cache.ListRightPop(redisKey);
}
public static string ListLeftPop(string redisKey)
{
return cache.ListLeftPop(redisKey);
}
public static T ListLeftPop<T>(string redisKey)
{
return cache.ListLeftPop<T>(redisKey);
}
public static T ListRightPop<T>(string redisKey)
{
return cache.ListRightPop<T>(redisKey);
}
public static long ListRightPush<T>(string redisKey, T redisValue)
{
return cache.ListRightPush(redisKey, redisValue);
}
public static long ListLeftPush<T>(string redisKey, T redisValue)
{
return cache.ListLeftPush(redisKey, redisValue);
}
public static long ListLength(string redisKey)
{
return cache.ListLength(redisKey);
}
public static string ListGetByIndex(string redisKey, long index)
{
return cache.ListGetByIndex(redisKey, index);
}
public static bool HashSet<T>(string redisKey, string hashField, T value)
{
return cache.HashSet(redisKey, hashField, value);
}
public static T HashGet<T>(string redisKey, string hashField)
{
return cache.HashGet<T>(redisKey, hashField);
}
public static string HashGetString(string redisKey, string hashField)
{
return cache.HashGetString(redisKey, hashField);
}
public static List<T> HashScan<T>(string redisKey, int pageSize, int pageOffset)
{
return cache.HashScan<T>(redisKey, pageSize, pageOffset);
}
public static long SortedSetLength(string redisKey)
{
return cache.SortedSetLength(redisKey);
}
public static bool SortedSetAdd<T>(string redisKey, T member, double score)
{
return cache.SortedSetAdd(redisKey, member, score);
}
public static bool SortedSetRemove<T>(string redisKey, T member)
{
return cache.SortedSetRemove(redisKey, member);
}
public static List<T> SortedSetRangeByScore<T>(string redisKey, double start, double stop)
{
return cache.SortedSetRangeByScore<T>(redisKey, start, stop);
}
public static List<T> SortedSetRangeByRank<T>(string redisKey, long start, long stop)
{
return cache.SortedSetRangeByRank<T>(redisKey, start, stop);
}
public static bool LockTake(string redisKey, string redisValue, TimeSpan cacheTime)
{
return cache.LockTake(redisKey, redisValue, cacheTime);
}
public static bool LockRelease(string redisKey, string redisValue)
{
return cache.LockRelease(redisKey, redisValue);
}
public static bool HashExists(string redisKey, string hashField)
{
return cache.HashExists(redisKey, hashField);
}
public static bool HashDelete(string redisKey, string hashField)
{
return cache.HashDelete(redisKey, hashField);
}
public static bool HashSet(string redisKey, string hashField, string value)
{
return cache.HashSet(redisKey, hashField, value);
}
public static bool HashSet(string redisKey, string hashField, long value)
{
return cache.HashSet(redisKey, hashField, value);
}
public static long HashGet(string redisKey, string hashField)
{
RedisValue t = (RedisValue)cache.HashGet(redisKey, hashField);
string str = t.ToString();
return long.Parse(str);
}
}
}
3、调用Redis
在本例中我使用用户流水的id作为sort的权重,而流水id是不会重复的,这样就可以直接存取指定id或指定id范围内的流水数据
using StackExchange.Redis;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace YChain.SinDouGame.Services
{
/// <summary>
/// 缓存
/// </summary>
public class RedisCacheExtension
{
private static readonly object syncFlowRoot = new object();
private static long maxflowId = -1;
private static long maxOrderId = -1;
private static long currentOrderId = -1;
private static long maxGuessId = -1;
private static long currentGuessId = -1;
private static RedisValue Token = Environment.MachineName;
ConcurrentDictionary<string, long> cdic = new ConcurrentDictionary<string, long>();
public static Dictionary<string, long> idset = new Dictionary<string, long>();
public static Dictionary<string, List<AccountFlowOperate>> userAccountFlow = new Dictionary<string, List<AccountFlowOperate>>();
/// <summary>
/// 插入流水
/// </summary>
/// <param name="username"></param>
/// <param name="data"></param>
/// <param name="dbContext"></param>
/// <returns></returns>
public static object InsertAccountFlow(string username, AccountFlowOperate data, IDbContext dbContext)
{
if (data == null)
return null;
string key = username;
bool has_insert_db = false;
lock (syncFlowRoot)
{
if (data.Id > 0)
has_insert_db = true;
data.CreatedTime = DateTime.Now;
data.UpdatedTime = DateTime.Now;
//生成插入的id,在redis中保存id,使用redis锁控制读写
if (RedisCache.Exists("accountflow_recordid"))
{
DateTime t1 = DateTime.Now;
DateTime t2 = t1.AddSeconds(5);
TimeSpan ts = t2 - t1;
if (RedisCache.LockTake("accountflowId_lock", Token, ts))
{
try
{
//自加1
data.Id = RedisCache.StringIncrement("accountflow_recordid");
}
catch (Exception ex)
{
}
finally
{
RedisCache.LockRelease("accountflowId_lock", Token);
}
}
else
{
RedisCache.LockRelease("accountflowId_lock", Token);
}
}
else
{
var lastflow = dbContext.Set<AccountFlowOperate>().OrderByDescending(p => p.Id).Take(1).ToList();
if (lastflow.Count() > 0)
{
maxflowId = lastflow[0].Id;
}
else
{
maxflowId = 0;
}
DateTime t1 = DateTime.Now;
DateTime t2 = t1.AddSeconds(5);
TimeSpan ts = t2 - t1;
if (RedisCache.LockTake("accountflowId_lock", Token, ts))
{
if (RedisCache.Exists("accountflow_recordid"))
{
try
{
data.Id = RedisCache.StringIncrement("accountflow_recordid");
}
catch (Exception ex)
{
}
finally
{
RedisCache.LockRelease("accountflowId_lock", Token);
}
}
else
{
try
{
RedisCache.Insert("accountflow_recordid", maxflowId.ToString());
data.Id = RedisCache.StringIncrement("accountflow_recordid");
}
catch (Exception ex)
{
}
finally
{
RedisCache.LockRelease("accountflowId_lock", Token);
}
}
}
}
//data.Id = ++maxflowId;
}
#region redis_sort_set
string redis_key = "sort_flow_" + username;
if (RedisCache.Exists(redis_key))
{
//将流水id最为权重,存储在sortset中
RedisCache.SortedSetAdd(redis_key, data, data.Id);
}
else
{
DateTime starttime = DateTime.Now.AddDays(-30);
List<AccountFlowOperate> accountflowList = dbContext.Set<AccountFlowOperate>().Where(p => p.AccountName == username && p.CreatedTime > starttime).OrderByDescending(p => p.Id).Take(1000).ToList();
foreach (var flow in accountflowList)
{
//将流水id最为权重,存储在sortset中
RedisCache.SortedSetAdd(redis_key, flow, flow.Id);
}
if (has_insert_db == false)
RedisCache.SortedSetAdd(redis_key, data, data.Id);
}
#endregion
return null;
}
/// <summary>
/// 获取用户的全部流水
/// </summary>
/// <param name="username"></param>
/// <param name="dbContext"></param>
/// <returns></returns>
public static List<AccountFlowOperate> GetAccountFlow(string username, IDbContext dbContext)
{
#region redis_sort_set
string redis_key = "sort_flow_" + username;
if (RedisCache.Exists(redis_key))
{
//先获取数据的总长度
long redis_length = RedisCache.SortedSetLength(redis_key);
List<AccountFlowOperate> accountflowList = new List<AccountFlowOperate>();
long current_length = 0;
//再多次取数据,每次只取1000行,通过测试如果一次性读写太多数据,读写的速度太慢,而多次少量读取则会非常快
while (current_length < redis_length)
{
accountflowList.AddRange(RedisCache.SortedSetRangeByRank<AccountFlowOperate>(redis_key, current_length, current_length + 1000 - 1));
current_length += 1000;
}
return accountflowList;
}
else
{
DateTime starttime = DateTime.Now.AddDays(-30);
List<AccountFlowOperate> accountflowList = dbContext.Set<AccountFlowOperate>().Where(p => p.AccountName == username && p.CreatedTime > starttime).OrderByDescending(p => p.Id).Take(1000).ToList();
foreach (var flow in accountflowList)
{
RedisCache.SortedSetAdd(redis_key, flow, flow.Id);
}
return accountflowList;
}
#endregion
}
/// <summary>
/// 通过start 和 stop 控制分页获取流水数据
/// </summary>
/// <param name="username"></param>
/// <param name="start"></param>
/// <param name="stop"></param>
/// <param name="dbContext"></param>
/// <param name="flow_length"></param>
/// <returns></returns>
public static List<AccountFlowOperate> GetAccountFlow(string username, long start, long stop, IDbContext dbContext, ref long flow_length)
{
#region redis_sort_set
string redis_key = "sort_flow_" + username;
if (RedisCache.Exists(redis_key))
{
flow_length = RedisCache.SortedSetLength(redis_key);
List<AccountFlowOperate> accountflowList = new List<AccountFlowOperate>();
if (stop > flow_length)
stop = flow_length - 1;
if (start > flow_length)
return accountflowList;
accountflowList.AddRange(RedisCache.SortedSetRangeByRank<AccountFlowOperate>(redis_key, start, stop));
return accountflowList;
}
else
{
DateTime starttime = DateTime.Now.AddDays(-30);
List<AccountFlowOperate> accountflowList = dbContext.Set<AccountFlowOperate>().Where(p => p.AccountName == username && p.CreatedTime > starttime).OrderByDescending(p => p.Id).Take(1000).ToList();
foreach (var flow in accountflowList)
{
RedisCache.SortedSetAdd(redis_key, flow, flow.Id);
}
flow_length = accountflowList.Count();
return RedisCache.SortedSetRangeByRank<AccountFlowOperate>(redis_key, start, stop);
}
#endregion
}