.Net5 WebApi中Redis的使用
Nuget安装Redis包
install-package StackExchange.Redis.Extensions.Core
install-package StackExchange.Redis.Extensions.AspNetCore
install-package StackExchange.Redis.Extensions.Newtonsoft
代码
Redis服务类 - 接口
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Levox.Framework.Core.Models.Inject;
namespace Levox.Framework.Redis
{
/// <summary>
/// 缓存服务 LastUpdateDate:2021-04-02 15:24:52.128 Author:Lingbug
/// </summary>
public interface ILevoxCacheUtil : IErpSingletonApplicationService
{
/// <summary>
/// 批量删除缓存 LastUpdateDate:2021-04-02 16:37:56.315 Author:Lingbug
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
Task<long> DeleteAsync(params string[] keys);
/// <summary>
/// 清空缓存 LastUpdateDate:2021-04-02 16:39:13.090 Author:Lingbug
/// </summary>
/// <returns></returns>
Task ClearAsync();
/// <summary>
/// 添加数据到缓存(string) - 相对过期时间 LastUpdateDate:2021-04-02 16:09:11.940 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiresIn">相对过期时间,为空则永不过期</param>
/// <returns>是否添加成功</returns>
Task<bool> AddStringAsync<T>(string key, T value, TimeSpan? expiresIn = null);
/// <summary>
/// 添加数据到缓存(string) - 绝对过期时间 LastUpdateDate:2021-04-02 16:09:26.020 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiresTime">绝对过期时间,为空则永不过期</param>
/// <returns>是否添加成功</returns>
Task<bool> AddStringAbsAsync<T>(string key, T value, DateTime? expiresTime = null);
/// <summary>
/// 从缓存中读取数据(单个) LastUpdateDate:2021-04-02 16:13:31.620 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
Task<T> GetValueAsync<T>(string key);
/// <summary>
/// 从缓存中读取数据(多个) LastUpdateDate:2021-04-02 16:14:46.852 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="keys"></param>
/// <returns></returns>
Task<IDictionary<string, T>> GetValuesAsync<T>(params string[] keys);
#region List
/// <summary>
/// 将缓存数据添加到指定key所在的集合队列中 LastUpdateDate:2021-04-06 09:24:14.126 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="values"></param>
/// <returns>当前该key所在的集合队列总长度</returns>
Task<long> EnQueue<T>(string key, params T[] values) where T : class;
/// <summary>
/// 从缓存中指定key的集合队列中读取并删除一条数据 LastUpdateDate:2021-04-06 09:26:27.797 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
Task<T> DeQueueSingle<T>(string key) where T : class;
/// <summary>
/// 从缓存中指定key的集合队列中读取并删除n条数据 LastUpdateDate:2021-04-06 09:26:47.247 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="n"></param>
/// <returns></returns>
Task<List<T>> DeQueueBatch<T>(string key, long n) where T : class;
#endregion
#region Hash
/// <summary>
/// 添加多个键值对到指定HashKey的缓存中 LastUpdateDate:2021-04-02 16:49:44.676 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hashKey"></param>
/// <param name="values"></param>
/// <returns></returns>
Task AddToHashAsync<T>(string hashKey, IDictionary<string, T> values);
/// <summary>
/// 从缓存中读取指定Hash -> 指定key的值(单个) LastUpdateDate:2021-04-02 16:58:12.352 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hashKey"></param>
/// <param name="key"></param>
/// <returns></returns>
Task<T> GetValueFromHashAsync<T>(string hashKey, string key);
/// <summary>
/// 从缓存中读取指定Hash -> 多个key的值(为空则读取所有keys) LastUpdateDate:2021-04-02 17:01:56.728 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hashKey"></param>
/// <param name="keys">为空则读取所有keys</param>
/// <returns></returns>
Task<Dictionary<string, T>> GetValuesFromHashAsync<T>(string hashKey, params string[] keys);
/// <summary>
/// 从缓存中删除指定HashKey -> 多个keys的值(为空则删除该HashKey的所有keys) LastUpdateDate:2021-04-02 17:10:58.182 Author:Lingbug
/// </summary>
/// <param name="hashKey"></param>
/// <param name="keys">为空则删除该HashKey的所有keys</param>
/// <returns></returns>
Task<long> DeleteValuesFromHashAsync(string hashKey, params string[] keys);
#endregion
#region MQ
/// <summary>
/// 订阅(监听)消息队列的消息(在发布前订阅,允许多端消费;在发布后订阅,只允许一次消费) LastUpdateDate:2021-04-25 10:38:20.413 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queueName">监听的队列名称</param>
/// <param name="onReceiveMessage">收到消息时回调</param>
/// <returns></returns>
Task SubscribeMessageAsync<T>(string queueName, Func<T, Task> onReceiveMessage) where T : class;
/// <summary>
/// 发布消息到消息队列 LastUpdateDate:2021-05-12 10:28:07.584 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queueName">要发布到的队列名称</param>
/// <param name="message">要发布的消息</param>
/// <param name="isSendOfflineMessage">是否发送离线消息</param>
/// <returns></returns>
Task<long> PublishMessageAsync<T>(string queueName, T message, bool isSendOfflineMessage) where T : class;
/ <summary>
/ 取消订阅(监听)指定消息队列 LastUpdateDate:2021-04-25 10:55:55.620 Author:Lingbug
/ </summary>
/ <typeparam name="T"></typeparam>
/ <param name="queueName">队列名称</param>
/ <param name="callback">回调(通常不用传,为空的话框架会在回调记录取消日志)</param>
/ <returns></returns>
//Task UnSubscribeMessage<T>(string queueName, Func<T, Task> callback = null) where T : class;
#endregion
}
}
Redis服务类 - 实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Levox.Framework.Core.Extensions;
using Levox.Framework.Core.Logger;
using Levox.Framework.Core.Mappers;
using Levox.Framework.Core.Models.Exceptions;
using StackExchange.Redis;
using StackExchange.Redis.Extensions.Core.Abstractions;
namespace Levox.Framework.Redis
{
/// <summary>
/// Redis缓存服务实现 LastUpdateDate:2021-04-02 15:26:20.480 Author:Lingbug
/// </summary>
public class LevoxRedisCacheUtil : ILevoxCacheUtil
{
/// <summary>
/// redis库索引
/// </summary>
private static int _dbIndex;
/// <summary>
/// 构造
/// </summary>
/// <param name="redisCacheClient"></param>
/// <param name="loggerUtil"></param>
public LevoxRedisCacheUtil(IRedisCacheClient redisCacheClient, ILoggerUtil loggerUtil)
{
//赋值
_redisCacheClient = redisCacheClient;
_loggerUtil = loggerUtil;
}
/// <summary>
/// redis服务
/// </summary>
private readonly IRedisCacheClient _redisCacheClient;
/// <summary>
/// 日志服务
/// </summary>
private readonly ILoggerUtil _loggerUtil;
/// <summary>
/// 批量删除缓存 LastUpdateDate:2021-04-02 16:37:56.315 Author:Lingbug
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
public async Task<long> DeleteAsync(params string[] keys)
{
if (keys.IsNullOrEmptyList()) return 0;
keys = keys.Where(r => !r.IsNullOrWhiteSpaceString()).ToArray();
if (keys.IsNullOrEmptyList()) return 0;
var db = GetDatabase();
return await db.RemoveAllAsync(keys);
}
/// <summary>
/// 清空缓存 LastUpdateDate:2021-04-02 16:39:13.090 Author:Lingbug
/// </summary>
/// <returns></returns>
public async Task ClearAsync()
{
var db = GetDatabase();
await db.FlushDbAsync();
}
/// <summary>
/// 添加数据到缓存(string) - 相对过期时间 LastUpdateDate:2021-04-02 16:09:11.940 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiresIn">相对过期时间,为空则永不过期</param>
/// <returns>是否添加成功</returns>
public async Task<bool> AddStringAsync<T>(string key, T value, TimeSpan? expiresIn = null)
{
if (key.IsNullOrWhiteSpaceString()) return false;
var db = GetDatabase();
if (expiresIn.HasValue)
return await db.AddAsync(key, value, expiresIn.Value);
else
return await db.AddAsync(key, value);
}
/// <summary>
/// 添加数据到缓存(string) - 绝对过期时间 LastUpdateDate:2021-04-02 16:09:26.020 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expiresTime">绝对过期时间,为空则永不过期</param>
/// <returns>是否添加成功</returns>
public async Task<bool> AddStringAbsAsync<T>(string key, T value, DateTime? expiresTime = null)
{
if (key.IsNullOrWhiteSpaceString()) return false;
var db = GetDatabase();
if (expiresTime.HasValue)
return await db.AddAsync(key, value, new DateTimeOffset(expiresTime.Value));
else
return await db.AddAsync(key, value);
}
/// <summary>
/// 从缓存中读取数据(单个) LastUpdateDate:2021-04-02 16:13:31.620 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public async Task<T> GetValueAsync<T>(string key)
{
if (key.IsNullOrWhiteSpaceString()) return default;
var db = GetDatabase();
return await db.GetAsync<T>(key);
}
/// <summary>
/// 从缓存中读取数据(多个) LastUpdateDate:2021-04-02 16:14:46.852 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="keys"></param>
/// <returns></returns>
public async Task<IDictionary<string, T>> GetValuesAsync<T>(params string[] keys)
{
if (keys.IsNullOrEmptyList()) return new Dictionary<string, T>();
keys = keys.Where(r => !r.IsNullOrWhiteSpaceString()).ToArray();
if (keys.IsNullOrEmptyList()) return new Dictionary<string, T>();
var db = GetDatabase();
return await db.GetAllAsync<T>(keys);
}
#region List
/// <summary>
/// 将缓存数据添加到指定key所在的集合队列中 LastUpdateDate:2021-04-06 09:24:14.126 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="values"></param>
/// <returns>当前该key所在的集合队列总长度</returns>
public async Task<long> EnQueue<T>(string key, params T[] values) where T : class
{
if (key.IsNullOrWhiteSpaceString() || values.IsNullOrEmptyList()) return 0;
var db = GetDatabase();
return await db.ListAddToLeftAsync(key, values, CommandFlags.None);
}
/// <summary>
/// 从缓存中指定key的集合队列中读取并删除一条数据 LastUpdateDate:2021-04-06 09:26:27.797 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public async Task<T> DeQueueSingle<T>(string key) where T : class
{
if (key.IsNullOrWhiteSpaceString()) return default;
var values = await DeQueueBatch<T>(key, 1);
return values.FirstOrDefault();
}
/// <summary>
/// 从缓存中指定key的集合队列中读取并删除n条数据 LastUpdateDate:2021-04-06 09:26:47.247 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="n"></param>
/// <returns></returns>
public async Task<List<T>> DeQueueBatch<T>(string key, long n) where T : class
{
var values = new List<T>();
if (key.IsNullOrWhiteSpaceString() || n <= 0) return values;
var db = GetDatabase();
for (int i = 0; i < n; i++)
{
var value = await db.ListGetFromRightAsync<T>(key);
values.Add(value);
}
return values;
}
#endregion
#region Hash
/// <summary>
/// 添加多个键值对到指定HashKey的缓存中 LastUpdateDate:2021-04-02 16:49:44.676 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hashKey"></param>
/// <param name="values"></param>
/// <returns></returns>
public async Task AddToHashAsync<T>(string hashKey, IDictionary<string, T> values)
{
if (hashKey.IsNullOrWhiteSpaceString() || values.IsNullOrEmptyList()) return;
var db = GetDatabase();
await db.HashSetAsync(hashKey, values);
}
/// <summary>
/// 从缓存中读取指定Hash -> 指定key的值(单个) LastUpdateDate:2021-04-02 16:58:12.352 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hashKey"></param>
/// <param name="key"></param>
/// <returns></returns>
public async Task<T> GetValueFromHashAsync<T>(string hashKey, string key)
{
if (hashKey.IsNullOrWhiteSpaceString() || key.IsNullOrWhiteSpaceString()) return default;
var db = GetDatabase();
return await db.HashGetAsync<T>(hashKey, key);
}
/// <summary>
/// 从缓存中读取指定Hash -> 多个key的值(为空则读取所有keys) LastUpdateDate:2021-04-02 17:01:56.728 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hashKey"></param>
/// <param name="keys">为空则读取所有keys</param>
/// <returns></returns>
public async Task<Dictionary<string, T>> GetValuesFromHashAsync<T>(string hashKey, params string[] keys)
{
if (hashKey.IsNullOrWhiteSpaceString()) return new Dictionary<string, T>();
var db = GetDatabase();
var values = await db.HashGetAllAsync<T>(hashKey);
if (values.IsNullOrEmptyList()) return values;
if (keys.IsNullOrEmptyList()) return values;
keys = keys.Where(r => !r.IsNullOrWhiteSpaceString()).ToArray();
if (keys.IsNullOrEmptyList()) return values;
return values.Where(r => keys.Contains(r.Key)).ToDictionary(r => r.Key, r => r.Value);
}
/// <summary>
/// 从缓存中删除指定HashKey -> 多个keys的值(为空则删除该HashKey的所有keys) LastUpdateDate:2021-04-02 17:10:58.182 Author:Lingbug
/// </summary>
/// <param name="hashKey"></param>
/// <param name="keys">为空则删除该HashKey的所有keys</param>
/// <returns></returns>
public async Task<long> DeleteValuesFromHashAsync(string hashKey, params string[] keys)
{
if (hashKey.IsNullOrWhiteSpaceString()) return 0;
var db = GetDatabase();
if (keys.IsNullOrEmptyList()) keys = (await db.HashKeysAsync(hashKey)).ToArray();
return await db.HashDeleteAsync(hashKey, keys);
}
#endregion
#region MQ
/// <summary>
/// 订阅(监听)消息队列的消息(在发布前订阅,允许多端消费;在发布后订阅(积压的消息),只允许一次消费) LastUpdateDate:2021-04-25 10:44:26.469 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queueName">监听的队列名称</param>
/// <param name="onReceiveMessage">收到消息时回调</param>
/// <returns></returns>
public async Task SubscribeMessageAsync<T>(string queueName, Func<T, Task> onReceiveMessage) where T : class
{
//校验
if (queueName.IsNullOrWhiteSpaceString()) throw new ErpFriendlyException("订阅(监听)消息队列的队列名称不能为空!");
//数据库
var db = GetDatabase();
//订阅
await db.SubscribeAsync(CreateChannel(queueName), onReceiveMessage);
//消费积压的消息
await SubscribePublishedMessageAsync(queueName, onReceiveMessage);
}
/// <summary>
/// 消费积压的消息 LastUpdateDate:2021-04-25 10:39:04.813 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queueName">队列名称</param>
/// <param name="onReceiveMessage">收到消息时回调</param>
/// <returns></returns>
private async Task<List<T>> SubscribePublishedMessageAsync<T>(string queueName, Func<T, Task> onReceiveMessage) where T : class
{
//集合
List<T> publishedMessageList = null;
//队列名称
string mqName = FormatMqKey(queueName);
//已发布的消息
T publishedMessage;
do
{
//出队
publishedMessage = await DeQueueSingle<T>(mqName);
if (publishedMessage != null)
{
//复制
var newMsg = publishedMessage.MapToHard<T>();
//初始化
publishedMessageList ??= new List<T>();
//添加到集合
publishedMessageList.Add(newMsg);
//补偿消费
await onReceiveMessage(newMsg);
}
} while (publishedMessage != null);
//返回
return publishedMessageList;
}
/// <summary>
/// 发布消息到消息队列 LastUpdateDate:2021-05-12 10:28:07.584 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queueName">要发布到的队列名称</param>
/// <param name="message">要发布的消息</param>
/// <param name="isSendOfflineMessage">是否发送离线消息</param>
/// <returns></returns>
public async Task<long> PublishMessageAsync<T>(string queueName, T message, bool isSendOfflineMessage) where T : class
{
//校验
if (queueName.IsNullOrWhiteSpaceString()) throw new ErpFriendlyException("发布消息到消息队列的队列名称不能为空!");
//数据库
var db = GetDatabase();
//发布
var count = await db.PublishAsync(CreateChannel(queueName), message);
//当前没有消费者,则存储消息
if (count <= 0 && isSendOfflineMessage) await EnQueue(FormatMqKey(queueName), message);
//返回
return count;
}
/// <summary>
/// 取消订阅(监听)指定消息队列 LastUpdateDate:2021-04-25 10:55:55.620 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queueName">队列名称</param>
/// <param name="callback">回调(通常不用传,为空的话框架会在回调记录取消日志)</param>
/// <returns></returns>
public async Task UnSubscribeMessageAsync<T>(string queueName, Func<T, Task> callback = null) where T : class
{
//校验
if (queueName.IsNullOrWhiteSpaceString()) throw new ErpFriendlyException("取消订阅(监听)消息队列的队列名称不能为空!");
//数据库
var db = GetDatabase();
//格式化
Func<T, Task> newCallback = callback ?? (async r =>
{
//记录日志
_loggerUtil.Debug("UnSubscribeMessage - 取消订阅消息:" + new
{
queueName,
callbackInput = r
}.SerializeToJson());
});
//订阅
await db.UnsubscribeAsync(CreateChannel(queueName), newCallback);
}
#endregion
#region 私有方法
/// <summary>
/// 获取指定数据库 LastUpdateDate:2021-04-27 17:57:37.912 Author:Lingbug
/// </summary>
/// <returns></returns>
private IRedisDatabase GetDatabase() => _redisCacheClient.GetDb(_dbIndex, "levoxErp_");
/// <summary>
/// 格式化队列名称 LastUpdateDate:2021-04-25 10:16:31.232 Author:Lingbug
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private string FormatMqKey(string key) => "mq_" + key;
/// <summary>
/// 创建管道 LastUpdateDate:2021-04-25 11:18:01.019 Author:Lingbug
/// </summary>
/// <param name="channelName"></param>
/// <returns></returns>
private RedisChannel CreateChannel(string channelName) => channelName;
#endregion
}
}
Startup的ConfigureServices注入Redis
using System.Linq;
using System.Reflection;
using Levox.Framework.Core.CommonUtils;
using Levox.Framework.Model.Input;
using Microsoft.Extensions.DependencyInjection;
using Levox.Framework.Core.Configuration;
using Levox.Framework.Core.Extensions;
using Levox.Framework.Core.Logger;
using Levox.Framework.Core.Models;
using StackExchange.Redis.Extensions.Newtonsoft;
using StackExchange.Redis.Extensions.Core.Configuration;
using Levox.Framework.Redis;
namespace Levox.Framework.WebApi.Extensions
{
/// <summary>
/// ERP缓存注入 LastUpdateDate:2021-04-02 17:59:53.348 Author:Lingbug
/// </summary>
public static class ErpRedisExtensions
{
/// <summary>
/// 注入缓存 LastUpdateDate:2021-04-02 18:32:27.888 Author:Lingbug
/// </summary>
/// <param name="services"></param>
/// <param name="option"></param>
public static void AddErpRedisCache(this IServiceCollection services, AddErpInjectOption option)
{
//默认key
if (option.CacheConfigKey.IsNullOrWhiteSpaceString()) option.CacheConfigKey = "LevoxRedis";
//读取配置
var configJson = ConfigurationUtil.GetSectionJson(option.CacheConfigKey);
if (configJson.IsNullOrWhiteSpaceString())
{
//提示
LoggerTestUtil.SimpleLog("请在配置文件中缓存配置信息!");
}
else
{
//记录日志
LoggerTestUtil.SimpleLog($"缓存配置信息【{nameof(AddErpInjectOption.CacheConfigKey)} = {option.CacheConfigKey}】:{configJson}");
//转为实体
var redisOption = configJson.DeserializeJsonToObject<RedisOption>();
//注入
services.AddStackExchangeRedisExtensions<NewtonsoftSerializer>(BuildRedisConfiguration(redisOption));
}
}
/// <summary>
/// 创建redis配置信息 LastUpdateDate:2021-04-06 10:03:56.499 Author:Lingbug
/// </summary>
/// <param name="redisOption"></param>
/// <returns></returns>
private static RedisConfiguration BuildRedisConfiguration(RedisOption redisOption)
{
//初始化
var redisConfiguration = new RedisConfiguration()
{
Hosts = new[]
{
new RedisHost()
{
Host = redisOption.Host.IsNullOrWhiteSpaceString() ? "127.0.0.1" : redisOption.Host,
Port = redisOption.Port ?? 6379
}
},
Database = redisOption.Database ?? 0,
Ssl = false,
ConnectTimeout = 10000,
AllowAdmin = true,
};
//密码
if (!redisOption.Password.IsNullOrWhiteSpaceString()) redisConfiguration.Password = redisOption.Password;
//赋值
SetDatabaseIndex(redisConfiguration.Database);
//返回
return redisConfiguration;
}
/// <summary>
/// 赋值全局redis库 LastUpdateDate:2021-04-27 18:01:02.223 Author:Lingbug
/// </summary>
/// <param name="dbIndex"></param>
private static void SetDatabaseIndex(int dbIndex)
{
//类型
var t = ReflectionUtiliy.LoadAssemblyByName("Levox.Framework.Redis").GetTypes().First(r => r.FullName == "Levox.Framework.Redis.LevoxRedisCacheUtil");
//字段
var f = t.GetFields(BindingFlags.Static | BindingFlags.NonPublic).First(r => r.Name == "_dbIndex");
//赋值
f.SetValue(null, dbIndex);
//记录日志
LoggerTestUtil.SimpleLog("redis数据库:" + f.GetValue(null));
}
}
}
在业务中使用Redis服务类(略)
Redis配置讲解(操作完记得重启Redis服务)
允许远程访问
1.修改两个配置文件:redis.windows.conf 和 redis.windows-service.conf
2.注释掉 bind 127.0.0.1
3.关闭保护模式 protected-mode no
密码
1.修改两个配置文件:redis.windows.conf 和 redis.windows-service.conf
2.开启 requirepass yourPassword