首先安装Redis https://github.com/MicrosoftArchive/redis/releases
https://github.com/cinience/RedisStudio/releases
Redis 启动和关闭 安装好之后,我们可以通过服务启动和关闭 Redis 了,我们可以查看系统的任务管理器,检查是否启动了 redis-server,下面是 redis-server 的启动和关闭命令:
$ redis-server.exe --service-start
$ redis-server.exe --service-stop
使用 cli 确认 redis-server 启动之后,我们可以执行 redis 目录里面的 redis-cli.exe 文件,这样就可以连接上 Redis 了。当然,我们也可以通过命令行 CMD 来链接 Redis。
可以直接进行 Redis 存取了:
$ redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> set firstKey "moyufed"
OK
127.0.0.1:6379> get firstKey
"moyufed"
127.0.0.1:6379>
增加密码 在 Redis 的安装目录中,有 redis.windows.conf ,redis.windows-service.conf 两个文件,我们使用记事本打开(推荐Notepad++),找到需要设置密码的行,可以 Ctrl + F 查找 “requirepass” 的行(大概386行位置),分别设置 Redis 密码(去掉前面的 “#”),例子:
requirepass moyufed
使用 Redis 修改好之后重启 redis-server ,此时连接 Redis 之后进行 Redis 存取需要登录,例子:
Administrator@WIN-1706081829 C:\Users\Administrator
$ redis-server.exe --service-stop
[42636] 25 Feb 18:42:53.622
Administrator@WIN-1706081829 C:\Users\Administrator
$ redis-server.exe --service-start
[38828] 25 Feb 18:42:58.576
Administrator@WIN-1706081829 C:\Users\Administrator
$ redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> set firstKey "moyufed"
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth moyufed
OK
127.0.0.1:6379> set firstKey "moyufed"
OK
127.0.0.1:6379> get firstKey
"moyufed"
127.0.0.1:6379>
参考文档 Window配置Redis环境和简单使用:https://www.cnblogs.com/wxjnew/p/9160855.html
Windows下Redis安装配置和使用注意事项:https://www.cnblogs.com/LMJBlogs/p/11550170.html
首先配置.NET6的安装环境
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="6.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="6.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NModbus4.NetCore" Version="2.0.1" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1" />
</ItemGroup>
</Project>
配置数据仓库:
public record Book
{
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
}
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
class BookConfig : IEntityTypeConfiguration<Book>
{
public void Configure(EntityTypeBuilder<Book> builder)
{
builder.ToTable("Books");
builder.HasKey(x => x.Id);
}
}
using Microsoft.EntityFrameworkCore;
public class MyDbContext : DbContext
{
private ConfigurationBuilder cfgBuilder = new ConfigurationBuilder();
private string path = Directory.GetCurrentDirectory();
public DbSet<Book> Books { get; set; }
public MyDbContext()
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
cfgBuilder.AddJsonFile("VariableNode.json", optional: true, reloadOnChange: true);
IConfigurationRoot configRoot = cfgBuilder.Build();
string conn = configRoot.GetSection("ConnectionStrings:SqliteConnectionString").Value;
string connString = "Data Source=" + path + conn;
optionsBuilder.UseSqlite(connString);
}
}
{
"ConnectionStrings": {
"SqliteConnectionString": "\\bin\\Debug\\net6.0\\Database\\DbSqlite.db",
"MySQLConnectionString": "server=192.168.85.102; database=OneToMany; uid=root; pwd=123456;"
},
"ModbusNode": {
"Id": 1,
"NodeClassId": 1,
"Name": "ModbusTCPClient",
"Description": "1#ZG上位机测试",
"ModbusType": "2000",
"ConnectTimeOut": "2000",
"CreateTime": "0",
"ReConnectTime": "5000",
"IsActive": "True",
"MaxErrorTimes": "1",
"KeyWay": "VarName",
"UseAlarmCheck": "True",
"ServerURL": "127.0.0.1",
"Port": "502",
"DataFormat": "ABCD",
"VarNum": "6",
"Type": "ModbusTCP",
"SlaveID": "1",
"Length": "10",
"Start": "0",
"Variable": [
{
"Id": 1,
"Number": "1",
"Name": "Float1",
"Description": "40001-40002",
"Type": "ModbusTCP",
"VarAddress": 0,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40001-40002低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40001-40002低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40001-40002高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40001-40002高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "Float",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
},
{
"Id": 2,
"Number": "2",
"Name": "Float2",
"Description": "40003-40004",
"Type": "ModbusTCP",
"VarAddress": 2,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40003-40004低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40003-40004低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40003-40004高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40003-40004高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "Float",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
},
{
"Id": 3,
"Number": "3",
"Name": "Float3",
"Description": "40005-40006",
"Type": "ModbusTCP",
"VarAddress": 4,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40005-40006低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40005-40006低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40005-40006高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40005-40006高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "Float",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
},
{
"Id": 4,
"Number": "4",
"Name": "Float4",
"Description": "40007-40008",
"Type": "ModbusTCP",
"VarAddress": 6,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40003-40004低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40003-40004低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40003-40004高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40003-40004高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "Float",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
},
{
"Id": 5,
"Number": "5",
"Name": "Ushort1",
"Description": "40009",
"Type": "ModbusTCP",
"VarAddress": 8,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40009低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40009低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40009高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40009高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "UShort",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
},
{
"Id": 6,
"Number": "6",
"Name": "Ushort2",
"Description": "40010",
"Type": "ModbusTCP",
"VarAddress": 9,
"Scale": "1",
"Offset": "0",
"Start": "0",
"AccessProperty": "读写",
"AlarmEnable": "True",
"ArchiveEnable": "True",
"SetLimitEnable": "True",
"AlarmType": "True",
"DiscreteAlarmType": "False",
"DiscreteAlarmPriority": "0",
"DiscreteAlarmNote": "null",
"LoLoAlarmEnable": "True",
"LoLoAlarmValue": "0",
"LoLoAlarmPriority": "0",
"LoLoAlarmNote": "40009低低报警",
"LowAlarmEnable": "True",
"LowAlarmValue": "20",
"LowAlarmPriority": "0",
"LowAlarmNote": "40009低报警",
"HighAlarmEnable": "True",
"HighAlarmValue": "80",
"HighAlarmPriority": "0",
"HighAlarmNote": "40009高报警",
"HiHiAlarmEnable": "True",
"HiHiAlarmValue": "100",
"HiHiAlarmPriority": "0",
"HiHiAlarmNote": "40009高高报警",
"ArchivePeriod": "80",
"SetLimitMax": "100",
"SetLimitMin": "0",
"VarType": "UShort",
"StoreType": "HoldingRegister4x",
"InsertTime": "0",
"Value": "0",
"ModbusGroupId": 1
}
]
}
}
namespace RedisDemonWebApi
{
public interface IRepository
{
Book? GetBooksByIdAsync(int a);
}
}
namespace RedisDemonWebApi
{
public class Repository : IRepository
{
private MyDbContext db;
public Repository(MyDbContext db)
{
this.db = db;
}
public Book? GetBooksByIdAsync(int a)
{
Book? book = db.Books.Where(x => x.Id == a).SingleOrDefault();
if (book==null)
{
return null;
}
else
{
return book;
}
}
}
}
依赖注入 :
global using RedisDemonWebApi;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddMemoryCache();
builder.Services.AddScoped<IMemoryCacheHelper, MemoryCacheHelper>();
builder.Services.AddDbContext<MyDbContext>();
builder.Services.AddScoped<IRepository, Repository>();
builder.Services.AddStackExchangeRedisCache(opt =>
{
opt.Configuration = "localhost";
opt.InstanceName = "cache1_";
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
控制器:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using System.Text.Json;
namespace RedisDemonWebApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{
private readonly IDistributedCache distCache;
private readonly IDistributedCacheHelper helper;
private readonly ILogger <TestController> logger;
private readonly IMemoryCache memCache;
private readonly IRepository repository;
public TestController(IRepository repository, IMemoryCache memCache, ILogger<TestController> logger, IDistributedCache distCache)
{
this.repository = repository;
this.memCache = memCache;
this.logger = logger;
this.distCache = distCache;
}
[HttpGet]
public async Task<ActionResult<Book?>> GetBookById(int Id)
{
logger.LogInformation($"开始执行GetBookById,Id={Id}");
Book? b = await memCache.GetOrCreateAsync("Book" + Id, async (e) =>
{
logger.LogInformation($"缓存中没找到,去数据库,Id={Id}");
return repository.GetBooksByIdAsync(Id);
});
logger.LogInformation($"GetOrCreateAsync结果{b}");
if (b == null)
{
return NotFound("找不到");
}
else
{
return Ok(b);
}
}
[HttpGet]
public async Task<ActionResult<Book?>> GetBookFromRedisById(int Id)
{
Book? book=null;
logger.LogInformation($"开始执行GetBookById,Id={Id}");
string? s = await distCache.GetStringAsync("Book" + Id);
if (s==null)
{
logger.LogInformation($"缓存中没找到,去数据库找,Id={Id}");
book = repository.GetBooksByIdAsync(Id);
var opt = new DistributedCacheEntryOptions();
opt.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30);
await distCache.SetStringAsync("Book" + Id, JsonSerializer.Serialize(book), opt);
logger.LogInformation($"在数据库中找到,Id={Id},将其序列化为字符串存入Redis");
}
else
{
book = JsonSerializer.Deserialize<Book?>(s);
logger.LogInformation($"直接在Redis中找到了,Id={Id}");
}
if (book==null)
{
logger.LogInformation($"数据库和Redis中都不存在Id={Id}的书籍");
return NotFound("不存在");
}
else
{
return book;
}
}
}
}
使用Swagger 测试 :
日志 :
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7063
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5063
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: D:\cSharpe\code\RedisDemon1\RedisDemonWebApi\
info: RedisDemonWebApi.Controllers.TestController[0]
开始执行GetBookById,Id=2
info: RedisDemonWebApi.Controllers.TestController[0]
缓存中没找到,去数据库找,Id=2
info: RedisDemonWebApi.Controllers.TestController[0]
在数据库中找到,Id=2,将其序列化为字符串存入Redis
info: RedisDemonWebApi.Controllers.TestController[0]
开始执行GetBookById,Id=2
info: RedisDemonWebApi.Controllers.TestController[0]
直接在Redis中找到了,Id=2
Redis中 :
如果查询的Id对应的内容不存在, 则Redis也会把null值存在Redis, 这样避免了缓存穿透的问题
|