使用 StackExchange.Redis 封装属于自己的 RedisHelper
目录
- 核心类 ConnectionMultiplexer
- 字符串(String)
- 哈希(Hash)
- 列表(List)
- 有序集合(sorted set)
- Key 操作
- 发布订阅
- 其他
简介
目前 .NET 使用访问 Redis 的的类库主流应该是 StackExchange.redis,自己参考网上的文章(也许是吃饱了撑着),也尝试做出简单的封装。
/// <summary>
/// Redis 助手
/// </summary>
public class RedisHelper
{
/// <summary>
/// 连接字符串
/// </summary>
private static readonly string ConnectionString; /// <summary>
/// redis 连接对象
/// </summary>
private static IConnectionMultiplexer _connMultiplexer; /// <summary>
/// 默认的 Key 值(用来当作 RedisKey 的前缀)
/// </summary>
private static readonly string DefaultKey; /// <summary>
/// 锁
/// </summary>
private static readonly object Locker = new object(); /// <summary>
/// 数据库
/// </summary>
private readonly IDatabase _db; /// <summary>
/// 获取 Redis 连接对象
/// </summary>
/// <returns></returns>
public IConnectionMultiplexer GetConnectionRedisMultiplexer()
{
if ((_connMultiplexer == null) || !_connMultiplexer.IsConnected)
{
lock (Locker)
{
if ((_connMultiplexer == null) || !_connMultiplexer.IsConnected)
_connMultiplexer = ConnectionMultiplexer.Connect(ConnectionString);
}
} return _connMultiplexer;
} #region 其它 public ITransaction GetTransaction()
{
return _db.CreateTransaction();
} #endregion 其它 #region 构造函数 static RedisHelper()
{
ConnectionString = ConfigurationManager.ConnectionStrings["RedisConnectionString"].ConnectionString;
_connMultiplexer = ConnectionMultiplexer.Connect(ConnectionString);
DefaultKey = ConfigurationManager.AppSettings["Redis.DefaultKey"];
AddRegisterEvent();
} public RedisHelper(int db = -1)
{
_db = _connMultiplexer.GetDatabase(db);
} #endregion 构造函数 #region String 操作 /// <summary>
/// 设置 key 并保存字符串(如果 key 已存在,则覆盖值)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public bool StringSet(string redisKey, string redisValue, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return _db.StringSet(redisKey, redisValue, expiry);
} /// <summary>
/// 保存多个 Key-value
/// </summary>
/// <param name="keyValuePairs"></param>
/// <returns></returns>
public bool StringSet(IEnumerable<KeyValuePair<RedisKey, RedisValue>> keyValuePairs)
{
keyValuePairs =
keyValuePairs.Select(x => new KeyValuePair<RedisKey, RedisValue>(AddKeyPrefix(x.Key), x.Value));
return _db.StringSet(keyValuePairs.ToArray());
} /// <summary>
/// 获取字符串
/// </summary>
/// <param name="redisKey"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public string StringGet(string redisKey, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return _db.StringGet(redisKey);
} /// <summary>
/// 存储一个对象(该对象会被序列化保存)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public bool StringSet<T>(string redisKey, T redisValue, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
var json = Serialize(redisValue);
return _db.StringSet(redisKey, json, expiry);
} /// <summary>
/// 获取一个对象(会进行反序列化)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public T StringGet<T>(string redisKey, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(_db.StringGet(redisKey));
} #region async /// <summary>
/// 保存一个字符串值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public async Task<bool> StringSetAsync(string redisKey, string redisValue, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.StringSetAsync(redisKey, redisValue, expiry);
} /// <summary>
/// 保存一组字符串值
/// </summary>
/// <param name="keyValuePairs"></param>
/// <returns></returns>
public async Task<bool> StringSetAsync(IEnumerable<KeyValuePair<RedisKey, RedisValue>> keyValuePairs)
{
keyValuePairs =
keyValuePairs.Select(x => new KeyValuePair<RedisKey, RedisValue>(AddKeyPrefix(x.Key), x.Value));
return await _db.StringSetAsync(keyValuePairs.ToArray());
} /// <summary>
/// 获取单个值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public async Task<string> StringGetAsync(string redisKey, string redisValue, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.StringGetAsync(redisKey);
} /// <summary>
/// 存储一个对象(该对象会被序列化保存)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public async Task<bool> StringSetAsync<T>(string redisKey, T redisValue, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
var json = Serialize(redisValue);
return await _db.StringSetAsync(redisKey, json, expiry);
} /// <summary>
/// 获取一个对象(会进行反序列化)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public async Task<T> StringGetAsync<T>(string redisKey, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(await _db.StringGetAsync(redisKey));
} #endregion async #endregion String 操作 #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 _db.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 _db.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 _db.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 _db.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);
_db.HashSet(redisKey, hashFields.ToArray());
} /// <summary>
/// 在 hash 中获取值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public RedisValue HashGet(string redisKey, string hashField)
{
redisKey = AddKeyPrefix(redisKey);
return _db.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 _db.HashGet(redisKey, hashField);
} /// <summary>
/// 从 hash 返回所有的字段值
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public IEnumerable<RedisValue> HashKeys(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.HashKeys(redisKey);
} /// <summary>
/// 返回 hash 中的所有值
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public RedisValue[] HashValues(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.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 = Serialize(value);
return _db.HashSet(redisKey, hashField, json);
} /// <summary>
/// 在 hash 中获取值(反序列化)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public T HashGet<T>(string redisKey, string hashField)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(_db.HashGet(redisKey, hashField));
} #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 _db.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 _db.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 _db.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 _db.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 _db.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 _db.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 _db.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 _db.HashKeysAsync(redisKey);
} /// <summary>
/// 返回 hash 中的所有值
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<IEnumerable<RedisValue>> HashValuesAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.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 _db.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 _db.HashGetAsync(redisKey, hashField));
} #endregion async #endregion Hash 操作 #region List 操作 /// <summary>
/// 移除并返回存储在该键列表的第一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public string ListLeftPop(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.ListLeftPop(redisKey);
} /// <summary>
/// 移除并返回存储在该键列表的最后一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public string ListRightPop(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.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 _db.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 _db.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 _db.ListLeftPush(redisKey, redisValue);
} /// <summary>
/// 返回列表上该键的长度,如果不存在,返回 0
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public long ListLength(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.ListLength(redisKey);
} /// <summary>
/// 返回在该列表上键所对应的元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public IEnumerable<RedisValue> ListRange(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.ListRange(redisKey);
} /// <summary>
/// 移除并返回存储在该键列表的第一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public T ListLeftPop<T>(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(_db.ListLeftPop(redisKey));
} /// <summary>
/// 移除并返回存储在该键列表的最后一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public T ListRightPop<T>(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(_db.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 _db.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 _db.ListLeftPush(redisKey, Serialize(redisValue));
} #region List-async /// <summary>
/// 移除并返回存储在该键列表的第一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<string> ListLeftPopAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.ListLeftPopAsync(redisKey);
} /// <summary>
/// 移除并返回存储在该键列表的最后一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<string> ListRightPopAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.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 _db.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 _db.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 _db.ListLeftPushAsync(redisKey, redisValue);
} /// <summary>
/// 返回列表上该键的长度,如果不存在,返回 0
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<long> ListLengthAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.ListLengthAsync(redisKey);
} /// <summary>
/// 返回在该列表上键所对应的元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<IEnumerable<RedisValue>> ListRangeAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.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 _db.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 _db.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 _db.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 _db.ListLeftPushAsync(redisKey, Serialize(redisValue));
} #endregion List-async #endregion List 操作 #region SortedSet 操作 /// <summary>
/// SortedSet 新增
/// </summary>
/// <param name="redisKey"></param>
/// <param name="member"></param>
/// <param name="score"></param>
/// <returns></returns>
public bool SortedSetAdd(string redisKey, string member, double score)
{
redisKey = AddKeyPrefix(redisKey);
return _db.SortedSetAdd(redisKey, member, score);
} /// <summary>
/// 在有序集合中返回指定范围的元素,默认情况下从低到高。
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public IEnumerable<RedisValue> SortedSetRangeByRank(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.SortedSetRangeByRank(redisKey);
} /// <summary>
/// 返回有序集合的元素个数
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public long SortedSetLength(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.SortedSetLength(redisKey);
} /// <summary>
/// 返回有序集合的元素个数
/// </summary>
/// <param name="redisKey"></param>
/// <param name="memebr"></param>
/// <returns></returns>
public bool SortedSetLength(string redisKey, string memebr)
{
redisKey = AddKeyPrefix(redisKey);
return _db.SortedSetRemove(redisKey, memebr);
} /// <summary>
/// SortedSet 新增
/// </summary>
/// <param name="redisKey"></param>
/// <param name="member"></param>
/// <param name="score"></param>
/// <returns></returns>
public bool SortedSetAdd<T>(string redisKey, T member, double score)
{
redisKey = AddKeyPrefix(redisKey);
var json = Serialize(member); return _db.SortedSetAdd(redisKey, json, score);
} #region SortedSet-Async /// <summary>
/// SortedSet 新增
/// </summary>
/// <param name="redisKey"></param>
/// <param name="member"></param>
/// <param name="score"></param>
/// <returns></returns>
public async Task<bool> SortedSetAddAsync(string redisKey, string member, double score)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.SortedSetAddAsync(redisKey, member, score);
} /// <summary>
/// 在有序集合中返回指定范围的元素,默认情况下从低到高。
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<IEnumerable<RedisValue>> SortedSetRangeByRankAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.SortedSetRangeByRankAsync(redisKey);
} /// <summary>
/// 返回有序集合的元素个数
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<long> SortedSetLengthAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.SortedSetLengthAsync(redisKey);
} /// <summary>
/// 返回有序集合的元素个数
/// </summary>
/// <param name="redisKey"></param>
/// <param name="memebr"></param>
/// <returns></returns>
public async Task<bool> SortedSetRemoveAsync(string redisKey, string memebr)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.SortedSetRemoveAsync(redisKey, memebr);
} /// <summary>
/// SortedSet 新增
/// </summary>
/// <param name="redisKey"></param>
/// <param name="member"></param>
/// <param name="score"></param>
/// <returns></returns>
public async Task<bool> SortedSetAddAsync<T>(string redisKey, T member, double score)
{
redisKey = AddKeyPrefix(redisKey);
var json = Serialize(member); return await _db.SortedSetAddAsync(redisKey, json, score);
} #endregion SortedSet-Async #endregion SortedSet 操作 #region key 操作 /// <summary>
/// 移除指定 Key
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public bool KeyDelete(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.KeyDelete(redisKey);
} /// <summary>
/// 移除指定 Key
/// </summary>
/// <param name="redisKeys"></param>
/// <returns></returns>
public long KeyDelete(IEnumerable<string> redisKeys)
{
var keys = redisKeys.Select(x => (RedisKey)AddKeyPrefix(x));
return _db.KeyDelete(keys.ToArray());
} /// <summary>
/// 校验 Key 是否存在
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public bool KeyExists(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.KeyExists(redisKey);
} /// <summary>
/// 重命名 Key
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisNewKey"></param>
/// <returns></returns>
public bool KeyRename(string redisKey, string redisNewKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.KeyRename(redisKey, redisNewKey);
} /// <summary>
/// 设置 Key 的时间
/// </summary>
/// <param name="redisKey"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public bool KeyExpire(string redisKey, TimeSpan? expiry)
{
redisKey = AddKeyPrefix(redisKey);
return _db.KeyExpire(redisKey, expiry);
} #region key-async /// <summary>
/// 移除指定 Key
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<bool> KeyDeleteAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.KeyDeleteAsync(redisKey);
} /// <summary>
/// 移除指定 Key
/// </summary>
/// <param name="redisKeys"></param>
/// <returns></returns>
public async Task<long> KeyDeleteAsync(IEnumerable<string> redisKeys)
{
var keys = redisKeys.Select(x => (RedisKey)AddKeyPrefix(x));
return await _db.KeyDeleteAsync(keys.ToArray());
} /// <summary>
/// 校验 Key 是否存在
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<bool> KeyExistsAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.KeyExistsAsync(redisKey);
} /// <summary>
/// 重命名 Key
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisNewKey"></param>
/// <returns></returns>
public async Task<bool> KeyRenameAsync(string redisKey, string redisNewKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.KeyRenameAsync(redisKey, redisNewKey);
} /// <summary>
/// 设置 Key 的时间
/// </summary>
/// <param name="redisKey"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public async Task<bool> KeyExpireAsync(string redisKey, TimeSpan? expiry)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.KeyExpireAsync(redisKey, expiry);
} #endregion key-async #endregion key 操作 #region 发布订阅 /// <summary>
/// 订阅
/// </summary>
/// <param name="channel"></param>
/// <param name="handle"></param>
public void Subscribe(RedisChannel channel, Action<RedisChannel, RedisValue> handle)
{
var sub = _connMultiplexer.GetSubscriber();
sub.Subscribe(channel, handle);
} /// <summary>
/// 发布
/// </summary>
/// <param name="channel"></param>
/// <param name="message"></param>
/// <returns></returns>
public long Publish(RedisChannel channel, RedisValue message)
{
var sub = _connMultiplexer.GetSubscriber();
return sub.Publish(channel, message);
} /// <summary>
/// 发布(使用序列化)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="channel"></param>
/// <param name="message"></param>
/// <returns></returns>
public long Publish<T>(RedisChannel channel, T message)
{
var sub = _connMultiplexer.GetSubscriber();
return sub.Publish(channel, Serialize(message));
} #region 发布订阅-async /// <summary>
/// 订阅
/// </summary>
/// <param name="channel"></param>
/// <param name="handle"></param>
public async Task SubscribeAsync(RedisChannel channel, Action<RedisChannel, RedisValue> handle)
{
var sub = _connMultiplexer.GetSubscriber();
await sub.SubscribeAsync(channel, handle);
} /// <summary>
/// 发布
/// </summary>
/// <param name="channel"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task<long> PublishAsync(RedisChannel channel, RedisValue message)
{
var sub = _connMultiplexer.GetSubscriber();
return await sub.PublishAsync(channel, message);
} /// <summary>
/// 发布(使用序列化)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="channel"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task<long> PublishAsync<T>(RedisChannel channel, T message)
{
var sub = _connMultiplexer.GetSubscriber();
return await sub.PublishAsync(channel, Serialize(message));
} #endregion 发布订阅-async #endregion 发布订阅 #region private method /// <summary>
/// 添加 Key 的前缀
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private static string AddKeyPrefix(string key)
{
return $"{DefaultKey}:{key}";
} #region 注册事件 /// <summary>
/// 添加注册事件
/// </summary>
private static void AddRegisterEvent()
{
_connMultiplexer.ConnectionRestored += ConnMultiplexer_ConnectionRestored;
_connMultiplexer.ConnectionFailed += ConnMultiplexer_ConnectionFailed;
_connMultiplexer.ErrorMessage += ConnMultiplexer_ErrorMessage;
_connMultiplexer.ConfigurationChanged += ConnMultiplexer_ConfigurationChanged;
_connMultiplexer.HashSlotMoved += ConnMultiplexer_HashSlotMoved;
_connMultiplexer.InternalError += ConnMultiplexer_InternalError;
_connMultiplexer.ConfigurationChangedBroadcast += ConnMultiplexer_ConfigurationChangedBroadcast;
} /// <summary>
/// 重新配置广播时(通常意味着主从同步更改)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_ConfigurationChangedBroadcast(object sender, EndPointEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChangedBroadcast)}: {e.EndPoint}");
} /// <summary>
/// 发生内部错误时(主要用于调试)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_InternalError(object sender, InternalErrorEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_InternalError)}: {e.Exception}");
} /// <summary>
/// 更改集群时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_HashSlotMoved(object sender, HashSlotMovedEventArgs e)
{
Console.WriteLine(
$"{nameof(ConnMultiplexer_HashSlotMoved)}: {nameof(e.OldEndPoint)}-{e.OldEndPoint} To {nameof(e.NewEndPoint)}-{e.NewEndPoint}, ");
} /// <summary>
/// 配置更改时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_ConfigurationChanged(object sender, EndPointEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChanged)}: {e.EndPoint}");
} /// <summary>
/// 发生错误时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_ErrorMessage(object sender, RedisErrorEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_ErrorMessage)}: {e.Message}");
} /// <summary>
/// 物理连接失败时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_ConnectionFailed(object sender, ConnectionFailedEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_ConnectionFailed)}: {e.Exception}");
} /// <summary>
/// 建立物理连接时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_ConnectionRestored(object sender, ConnectionFailedEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_ConnectionRestored)}: {e.Exception}");
} #endregion 注册事件 /// <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;
}
} #endregion private method
}
核心类 ConnectionMultiplexer
在 StackExchange.Redis 中最核心(中枢)的是 ConnectionMultiplexer 类,在所有调用之间它的实例对象应该被设计为在整个应用程序域中为共享和重用的,并不应该为每一个操作都创建一个 ConnectionMultiplexer 对象实例,也就是说我们可以使用常见的单例模式进行创建。
虽然 ConnectionMultiplexer 实现了 IDisposable 接口,但这并不意味着需要使用 using 进行释放,因为创建一个 ConnectionMultiplexer 对象是十分昂贵的 , 所以最好的是我们一直重用一个 ConnectionMultiplexer 对象。
/// <summary>
/// 连接字符串
/// </summary>
private static readonly string ConnectionString; /// <summary>
/// redis 连接对象
/// </summary>
private static IConnectionMultiplexer _connMultiplexer; /// <summary>
/// 默认的 Key 值(用来当作 RedisKey 的前缀)
/// </summary>
private static readonly string DefaultKey; /// <summary>
/// 锁
/// </summary>
private static readonly object Locker = new object(); /// <summary>
/// 数据库
/// </summary>
private readonly IDatabase _db; /// <summary>
/// 获取 Redis 连接对象
/// </summary>
/// <returns></returns>
public IConnectionMultiplexer GetConnectionRedisMultiplexer()
{
if ((_connMultiplexer == null) || !_connMultiplexer.IsConnected)
{
lock (Locker)
{
if ((_connMultiplexer == null) || !_connMultiplexer.IsConnected)
_connMultiplexer = ConnectionMultiplexer.Connect(ConnectionString);
}
} return _connMultiplexer;
}
我选择让这些静态变量的字段在静态构造函数中进行统一的初始化,如连接字符串,ConnectionMultiplexer 对象和注册事件等。
#region 构造函数 static RedisHelper()
{
ConnectionString = ConfigurationManager.ConnectionStrings["RedisConnectionString"].ConnectionString;
_connMultiplexer = ConnectionMultiplexer.Connect(ConnectionString);
DefaultKey = ConfigurationManager.AppSettings["Redis.DefaultKey"];
AddRegisterEvent();
} public RedisHelper(int db = -1)
{
_db = _connMultiplexer.GetDatabase(db);
} #endregion 构造函数
#region 注册事件 /// <summary>
/// 添加注册事件
/// </summary>
private static void AddRegisterEvent()
{
ConnMultiplexer.ConnectionRestored += ConnMultiplexer_ConnectionRestored;
ConnMultiplexer.ConnectionFailed += ConnMultiplexer_ConnectionFailed;
ConnMultiplexer.ErrorMessage += ConnMultiplexer_ErrorMessage;
ConnMultiplexer.ConfigurationChanged += ConnMultiplexer_ConfigurationChanged;
ConnMultiplexer.HashSlotMoved += ConnMultiplexer_HashSlotMoved;
ConnMultiplexer.InternalError += ConnMultiplexer_InternalError;
ConnMultiplexer.ConfigurationChangedBroadcast += ConnMultiplexer_ConfigurationChangedBroadcast;
} /// <summary>
/// 重新配置广播时(通常意味着主从同步更改)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_ConfigurationChangedBroadcast(object sender, EndPointEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChangedBroadcast)}: {e.EndPoint}");
} /// <summary>
/// 发生内部错误时(主要用于调试)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_InternalError(object sender, InternalErrorEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_InternalError)}: {e.Exception}");
} /// <summary>
/// 更改集群时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_HashSlotMoved(object sender, HashSlotMovedEventArgs e)
{
Console.WriteLine(
$"{nameof(ConnMultiplexer_HashSlotMoved)}: {nameof(e.OldEndPoint)}-{e.OldEndPoint} To {nameof(e.NewEndPoint)}-{e.NewEndPoint}, ");
} /// <summary>
/// 配置更改时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_ConfigurationChanged(object sender, EndPointEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChanged)}: {e.EndPoint}");
} /// <summary>
/// 发生错误时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_ErrorMessage(object sender, RedisErrorEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_ErrorMessage)}: {e.Message}");
} /// <summary>
/// 物理连接失败时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_ConnectionFailed(object sender, ConnectionFailedEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_ConnectionFailed)}: {e.Exception}");
} /// <summary>
/// 建立物理连接时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void ConnMultiplexer_ConnectionRestored(object sender, ConnectionFailedEventArgs e)
{
Console.WriteLine($"{nameof(ConnMultiplexer_ConnectionRestored)}: {e.Exception}");
} #endregion 注册事件
这里的 Redis.DefaultKey 和 RedisConnectionString 对应配置文件中 App.Config。
DefaultKey(默认 Key)的作用是给 redisKey 值添加一个前缀,我这里使用了命名空间作为了前缀,在 Redis 可视化工具中可以更直观的进行显示(以“:”进行字符串的拼接)。
字符串(String)
存储字符串值。所有的同步方法都带有对应的异步方法,所以也进行了简单的封装。比较常用的应该是字符串操作,直接将 value 序列化存放到 redis 中。
#region String 操作 /// <summary>
/// 设置 key 并保存字符串(如果 key 已存在,则覆盖值)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public bool StringSet(string redisKey, string redisValue, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return _db.StringSet(redisKey, redisValue, expiry);
} /// <summary>
/// 保存多个 Key-value
/// </summary>
/// <param name="keyValuePairs"></param>
/// <returns></returns>
public bool StringSet(IEnumerable<KeyValuePair<RedisKey, RedisValue>> keyValuePairs)
{
keyValuePairs =
keyValuePairs.Select(x => new KeyValuePair<RedisKey, RedisValue>(AddKeyPrefix(x.Key), x.Value));
return _db.StringSet(keyValuePairs.ToArray());
} /// <summary>
/// 获取字符串
/// </summary>
/// <param name="redisKey"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public string StringGet(string redisKey, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return _db.StringGet(redisKey);
} /// <summary>
/// 存储一个对象(该对象会被序列化保存)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public bool StringSet<T>(string redisKey, T redisValue, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
var json = Serialize(redisValue);
return _db.StringSet(redisKey, json, expiry);
} /// <summary>
/// 获取一个对象(会进行反序列化)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public T StringGet<T>(string redisKey, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(_db.StringGet(redisKey));
} #region async /// <summary>
/// 保存一个字符串值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public async Task<bool> StringSetAsync(string redisKey, string redisValue, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.StringSetAsync(redisKey, redisValue, expiry);
} /// <summary>
/// 保存一组字符串值
/// </summary>
/// <param name="keyValuePairs"></param>
/// <returns></returns>
public async Task<bool> StringSetAsync(IEnumerable<KeyValuePair<RedisKey, RedisValue>> keyValuePairs)
{
keyValuePairs =
keyValuePairs.Select(x => new KeyValuePair<RedisKey, RedisValue>(AddKeyPrefix(x.Key), x.Value));
return await _db.StringSetAsync(keyValuePairs.ToArray());
} /// <summary>
/// 获取单个值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public async Task<string> StringGetAsync(string redisKey, string redisValue, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.StringGetAsync(redisKey);
} /// <summary>
/// 存储一个对象(该对象会被序列化保存)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisValue"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public async Task<bool> StringSetAsync<T>(string redisKey, T redisValue, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
var json = Serialize(redisValue);
return await _db.StringSetAsync(redisKey, json, expiry);
} /// <summary>
/// 获取一个对象(会进行反序列化)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public async Task<T> StringGetAsync<T>(string redisKey, TimeSpan? expiry = null)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(await _db.StringGetAsync(redisKey));
} #endregion async #endregion String 操作
哈希(Hash)
哈希是一个 string 类型的 field 和 value 的映射表,哈希特别适合用于存储对象。
#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 _db.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 _db.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 _db.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 _db.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);
_db.HashSet(redisKey, hashFields.ToArray());
} /// <summary>
/// 在 hash 中获取值
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public RedisValue HashGet(string redisKey, string hashField)
{
redisKey = AddKeyPrefix(redisKey);
return _db.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 _db.HashGet(redisKey, hashField);
} /// <summary>
/// 从 hash 返回所有的字段值
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public IEnumerable<RedisValue> HashKeys(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.HashKeys(redisKey);
} /// <summary>
/// 返回 hash 中的所有值
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public RedisValue[] HashValues(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.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 = Serialize(value);
return _db.HashSet(redisKey, hashField, json);
} /// <summary>
/// 在 hash 中获取值(反序列化)
/// </summary>
/// <param name="redisKey"></param>
/// <param name="hashField"></param>
/// <returns></returns>
public T HashGet<T>(string redisKey, string hashField)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(_db.HashGet(redisKey, hashField));
} #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 _db.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 _db.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 _db.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 _db.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 _db.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 _db.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 _db.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 _db.HashKeysAsync(redisKey);
} /// <summary>
/// 返回 hash 中的所有值
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<IEnumerable<RedisValue>> HashValuesAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.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 _db.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 _db.HashGetAsync(redisKey, hashField));
} #endregion async #endregion Hash 操作
列表(List)
列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。
#region List 操作 /// <summary>
/// 移除并返回存储在该键列表的第一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public string ListLeftPop(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.ListLeftPop(redisKey);
} /// <summary>
/// 移除并返回存储在该键列表的最后一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public string ListRightPop(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.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 _db.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 _db.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 _db.ListLeftPush(redisKey, redisValue);
} /// <summary>
/// 返回列表上该键的长度,如果不存在,返回 0
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public long ListLength(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.ListLength(redisKey);
} /// <summary>
/// 返回在该列表上键所对应的元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public IEnumerable<RedisValue> ListRange(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.ListRange(redisKey);
} /// <summary>
/// 移除并返回存储在该键列表的第一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public T ListLeftPop<T>(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(_db.ListLeftPop(redisKey));
} /// <summary>
/// 移除并返回存储在该键列表的最后一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public T ListRightPop<T>(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return Deserialize<T>(_db.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 _db.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 _db.ListLeftPush(redisKey, Serialize(redisValue));
} #region List-async /// <summary>
/// 移除并返回存储在该键列表的第一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<string> ListLeftPopAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.ListLeftPopAsync(redisKey);
} /// <summary>
/// 移除并返回存储在该键列表的最后一个元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<string> ListRightPopAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.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 _db.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 _db.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 _db.ListLeftPushAsync(redisKey, redisValue);
} /// <summary>
/// 返回列表上该键的长度,如果不存在,返回 0
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<long> ListLengthAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.ListLengthAsync(redisKey);
} /// <summary>
/// 返回在该列表上键所对应的元素
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<IEnumerable<RedisValue>> ListRangeAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.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 _db.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 _db.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 _db.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 _db.ListLeftPushAsync(redisKey, Serialize(redisValue));
} #endregion List-async #endregion List 操作
有序集合(sorted set)
有序集合成员是唯一的,这就意味着集合中不能出现重复的数据。
#region SortedSet 操作 /// <summary>
/// SortedSet 新增
/// </summary>
/// <param name="redisKey"></param>
/// <param name="member"></param>
/// <param name="score"></param>
/// <returns></returns>
public bool SortedSetAdd(string redisKey, string member, double score)
{
redisKey = AddKeyPrefix(redisKey);
return _db.SortedSetAdd(redisKey, member, score);
} /// <summary>
/// 在有序集合中返回指定范围的元素,默认情况下从低到高。
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public IEnumerable<RedisValue> SortedSetRangeByRank(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.SortedSetRangeByRank(redisKey);
} /// <summary>
/// 返回有序集合的元素个数
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public long SortedSetLength(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.SortedSetLength(redisKey);
} /// <summary>
/// 返回有序集合的元素个数
/// </summary>
/// <param name="redisKey"></param>
/// <param name="memebr"></param>
/// <returns></returns>
public bool SortedSetLength(string redisKey, string memebr)
{
redisKey = AddKeyPrefix(redisKey);
return _db.SortedSetRemove(redisKey, memebr);
} /// <summary>
/// SortedSet 新增
/// </summary>
/// <param name="redisKey"></param>
/// <param name="member"></param>
/// <param name="score"></param>
/// <returns></returns>
public bool SortedSetAdd<T>(string redisKey, T member, double score)
{
redisKey = AddKeyPrefix(redisKey);
var json = Serialize(member); return _db.SortedSetAdd(redisKey, json, score);
} #region SortedSet-Async /// <summary>
/// SortedSet 新增
/// </summary>
/// <param name="redisKey"></param>
/// <param name="member"></param>
/// <param name="score"></param>
/// <returns></returns>
public async Task<bool> SortedSetAddAsync(string redisKey, string member, double score)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.SortedSetAddAsync(redisKey, member, score);
} /// <summary>
/// 在有序集合中返回指定范围的元素,默认情况下从低到高。
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<IEnumerable<RedisValue>> SortedSetRangeByRankAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.SortedSetRangeByRankAsync(redisKey);
} /// <summary>
/// 返回有序集合的元素个数
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<long> SortedSetLengthAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.SortedSetLengthAsync(redisKey);
} /// <summary>
/// 返回有序集合的元素个数
/// </summary>
/// <param name="redisKey"></param>
/// <param name="memebr"></param>
/// <returns></returns>
public async Task<bool> SortedSetRemoveAsync(string redisKey, string memebr)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.SortedSetRemoveAsync(redisKey, memebr);
} /// <summary>
/// SortedSet 新增
/// </summary>
/// <param name="redisKey"></param>
/// <param name="member"></param>
/// <param name="score"></param>
/// <returns></returns>
public async Task<bool> SortedSetAddAsync<T>(string redisKey, T member, double score)
{
redisKey = AddKeyPrefix(redisKey);
var json = Serialize(member); return await _db.SortedSetAddAsync(redisKey, json, score);
} #endregion SortedSet-Async #endregion SortedSet 操作
Key 操作
#region key 操作 /// <summary>
/// 移除指定 Key
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public bool KeyDelete(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.KeyDelete(redisKey);
} /// <summary>
/// 移除指定 Key
/// </summary>
/// <param name="redisKeys"></param>
/// <returns></returns>
public long KeyDelete(IEnumerable<string> redisKeys)
{
var keys = redisKeys.Select(x => (RedisKey)AddKeyPrefix(x));
return _db.KeyDelete(keys.ToArray());
} /// <summary>
/// 校验 Key 是否存在
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public bool KeyExists(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.KeyExists(redisKey);
} /// <summary>
/// 重命名 Key
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisNewKey"></param>
/// <returns></returns>
public bool KeyRename(string redisKey, string redisNewKey)
{
redisKey = AddKeyPrefix(redisKey);
return _db.KeyRename(redisKey, redisNewKey);
} /// <summary>
/// 设置 Key 的时间
/// </summary>
/// <param name="redisKey"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public bool KeyExpire(string redisKey, TimeSpan? expiry)
{
redisKey = AddKeyPrefix(redisKey);
return _db.KeyExpire(redisKey, expiry);
} #region key-async /// <summary>
/// 移除指定 Key
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<bool> KeyDeleteAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.KeyDeleteAsync(redisKey);
} /// <summary>
/// 移除指定 Key
/// </summary>
/// <param name="redisKeys"></param>
/// <returns></returns>
public async Task<long> KeyDeleteAsync(IEnumerable<string> redisKeys)
{
var keys = redisKeys.Select(x => (RedisKey)AddKeyPrefix(x));
return await _db.KeyDeleteAsync(keys.ToArray());
} /// <summary>
/// 校验 Key 是否存在
/// </summary>
/// <param name="redisKey"></param>
/// <returns></returns>
public async Task<bool> KeyExistsAsync(string redisKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.KeyExistsAsync(redisKey);
} /// <summary>
/// 重命名 Key
/// </summary>
/// <param name="redisKey"></param>
/// <param name="redisNewKey"></param>
/// <returns></returns>
public async Task<bool> KeyRenameAsync(string redisKey, string redisNewKey)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.KeyRenameAsync(redisKey, redisNewKey);
} /// <summary>
/// 设置 Key 的时间
/// </summary>
/// <param name="redisKey"></param>
/// <param name="expiry"></param>
/// <returns></returns>
public async Task<bool> KeyExpireAsync(string redisKey, TimeSpan? expiry)
{
redisKey = AddKeyPrefix(redisKey);
return await _db.KeyExpireAsync(redisKey, expiry);
} #endregion key-async #endregion key 操作
发布订阅
一般会使用第三方的 MQ,如 RabbitMQ。
#region 发布订阅 /// <summary>
/// 订阅
/// </summary>
/// <param name="channel"></param>
/// <param name="handle"></param>
public void Subscribe(RedisChannel channel, Action<RedisChannel, RedisValue> handle)
{
var sub = ConnMultiplexer.GetSubscriber();
sub.Subscribe(channel, handle);
} /// <summary>
/// 发布
/// </summary>
/// <param name="channel"></param>
/// <param name="message"></param>
/// <returns></returns>
public long Publish(RedisChannel channel, RedisValue message)
{
var sub = ConnMultiplexer.GetSubscriber();
return sub.Publish(channel, message);
} /// <summary>
/// 发布(使用序列化)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="channel"></param>
/// <param name="message"></param>
/// <returns></returns>
public long Publish<T>(RedisChannel channel, T message)
{
var sub = ConnMultiplexer.GetSubscriber();
return sub.Publish(channel, Serialize(message));
} #region 发布订阅-async /// <summary>
/// 订阅
/// </summary>
/// <param name="channel"></param>
/// <param name="handle"></param>
public async Task SubscribeAsync(RedisChannel channel, Action<RedisChannel, RedisValue> handle)
{
var sub = ConnMultiplexer.GetSubscriber();
await sub.SubscribeAsync(channel, handle);
} /// <summary>
/// 发布
/// </summary>
/// <param name="channel"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task<long> PublishAsync(RedisChannel channel, RedisValue message)
{
var sub = ConnMultiplexer.GetSubscriber();
return await sub.PublishAsync(channel, message);
} /// <summary>
/// 发布(使用序列化)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="channel"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task<long> PublishAsync<T>(RedisChannel channel, T message)
{
var sub = ConnMultiplexer.GetSubscriber();
return await sub.PublishAsync(channel, Serialize(message));
} #endregion 发布订阅-async #endregion 发布订阅
其他
这里使用了二进制序列化器进行序列化操作。
/// <summary>
/// 添加 Key 的前缀
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private static string AddKeyPrefix(string key)
{
return $"{DefaultKey}:{key}";
} /// <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;
}
}
测试代码:
【备注】内部还有很多的接口和方法没有进行封装,还需要自己进行封装。
【GitHub】https://github.com/liqingwen2015/Wen.Helpers
使用 StackExchange.Redis 封装属于自己的 RedisHelper的更多相关文章
- [C#] 使用 StackExchange.Redis 封装属于自己的 RedisHelper
使用 StackExchange.Redis 封装属于自己的 RedisHelper 目录 核心类 ConnectionMultiplexer 字符串(String) 哈希(Hash) 列表(List ...
- [C#] 使用 StackExchange.Redis 封装属于自己的 Helper
使用 StackExchange.Redis 封装属于自己的 Helper 目录 核心类 ConnectionMultiplexer 字符串(String) 哈希(Hash) 列表(List) 有序集 ...
- c#使用 StackExchange.Redis 封装 RedisHelper
公司一直在用.net自带的缓存,大家都知道.net自带缓存的缺点,就不多说了,不知道的可以查一查,领导最近在说分布式缓存,我们选的是redis,领导让我不忙的时候封装一下,搜索了两天,选了选第三方的插 ...
- StackExchange.Redis 封装
博主最近开始玩Redis啊~~ 看了很多Redis的文章,感觉有点云里雾里的,之前看到是ServiceStack.Redis,看了一些大佬封装的Helper类,还是懵懵的QAQ 没办法啊只能硬着**上 ...
- 功能比较全的StackExchange.Redis封装帮助类(.Net/C#)
Redis官网https://redis.io/ 以下内容未全部验证,如有问题请指出 //static NewtonsoftSerializer serializer = new Newtonsoft ...
- DotNet Core 使用 StackExchange.Redis 简单封装和实现分布式锁
前言 公司的项目以前一直使用 CSRedis 这个类库来操作 Redis,最近增加了一些新功能,会存储一些比较大的数据,内测的时候发现其中有两台服务器会莫名的报错 Unexpected respons ...
- C# StackExchange.Redis 用法总结
安装 StackExchange.Redis 在 NuGet 中搜索 StackExchange.Redis 和 Newtonsoft.Json,直接点击按钮安装即可. StackExchange.R ...
- redis的安装、启动、主从配置,以及.Net下StackExchange.Redis的使用
开门见山,Linux下配个环境真是苦逼死了,这里记录一下,囧 一.环境 服务端:Ubuntu16.04 LTS(虚拟机,redis官方没有window发布版本,而且在Linux下运行更稳定) 客户端: ...
- StackExchange.Redis 二次封装
在NuGet直接搜索StackExchange.Redis,下载引用包: 帮助类: public class RedisUtils { /// <summary> /// redis配置文 ...
随机推荐
- h5页面长按保存图片
由于之前几乎没有使用过canvas:今天遇到了一个很棘手的问题.canvas生成后,然后长按保存到手机. 正常的流程应该是先用canvas进行画图,然后再把canvas转成地址,最后再把转化的地址给i ...
- 关于Extjs的窗口拖拽,改变大小,背景淡化问题
大部分Extjs的Windows问题:在Extjs4代码中,只要加几句话: frame:true, //这个窗口的边边是圆的 border : false , //窗口没有边框 draggable: ...
- P1036 选数(DFS)
题目 https://www.luogu.org/problemnew/show/P1036 思路 搜索,使用递归实现dfs,所有数字遍历一遍,当取遍所有数组的index(扫了一遍,并非一定是选取了) ...
- mysql服务无法启动(1067错误)时数据备份的经验
mysql服务无法启动(1067错误)时数据备份的经验 背景 方法 背景 在已安装MySQL5.5的情况下,再次安装 MySQL5.7时,因为MySQL5.7是压缩文件安装的方式,复制MySQL5.5 ...
- HDU_5783_DivideTheSequence
HDU_5783_DivideTheSequence 点击打开链接 题意: 生成尽量多的连续的子串,且子串的前缀和大于等于0,输出符合题意的子串的数量. 这题目是参加四月份的个人训练赛遇到的,挺水的 ...
- notepad++使用NppFTP连接linux,编写shell脚本无法保存上传的问题
下载安装NppFTP插件之后,重启打开notepad++连接到linux主机,之后进行编辑shell脚本,出现无法保存上传至linux主机的问题. 分析的原因:可能的原因是Windows防火墙阻止了应 ...
- 洛谷 1017 进制转换 (NOIp2000提高组T1)
[题解] 纯模拟题. 我们都知道十进制数化成m进制数可以用短除法,即除m取余.逆序排列.而m进制数化为十进制数,按权展开求和即可. 但在本题中进制的基数R可能为负数,我们知道a%R的符号与R一致,也就 ...
- [USACO07OCT]障碍路线Obstacle Course
题目描述 Consider an N x N (1 <= N <= 100) square field composed of 1 by 1 tiles. Some of these ti ...
- O - Treats for the Cows 区间DP
FJ has purchased N (1 <= N <= 2000) yummy treats for the cows who get money for giving vast am ...
- MyBatis3错误:Parameter 'id' not found. Available parameters are [arg2, arg1, arg0, param3, param1, param2]或者Parameter '0' not found. Available parameters are [arg2, arg1, arg0, param3, param1, param2]
这个问题涉及到MyBatis3在使用select节点查询时传递多个参数的问题.问题分析如下: 1.如果是单个查询一般是这样配置: <select id="getUserArticles ...