第10 CURD操作与RedisCache缓存的强制清理的实现

news2024/9/22 21:25:56

using System.Net;

using Microsoft.Extensions.Caching.Distributed;

using Core.Caching;

using Core.Configuration;

using StackExchange.Redis;

namespace Services.Caching

{

    /// <summary>

    /// Redis分布式缓存数据库软件管理器--类】

    /// <remarks>

    /// 摘要:

    ///    通过该类中的方法成员实现了通过“StackExchange.Redis”中间件实例对Redis软件缓存数据更加底层的操作及其的“DistributedCacheManager”抽象类的实例化。

    /// </remarks>

    /// </summary>

    public class RedisCacheManager : DistributedCacheManager

    {

        #region 变量--私有/保护

        /// <summary>

        /// Redis连接封装器】

        /// <remarks>

        /// 摘要:

        ///     Redis连接封装器的1个指定实例。

        /// </remarks>

        /// </summary>

        private static RedisConnectionWrapper _connectionWrapper;

        /// <summary>

        /// 【数据库】

        /// <remarks>

        /// 摘要:

        ///     用于建立当前程序与Redis分布式缓存数据库软件中分布式缓存数据库的连接。

        /// </remarks>

        /// </summary>

        private readonly IDatabase _db;

        #endregion

        #region 拷贝构造方法

        /// <param name="appSettings">应用配置类的1个指定实例。</param>

        /// <param name="distributedCache">分布式缓存接口实例,该实例实际上是:“StackExchange.Redis”中间件的实例,通过该实例实现当前程序通过“StackExchange.Redis”中间件的实例与Redis分布式缓存数据库的交互操作。</param>

        /// <summary>

        /// 【拷贝构造方法】

        /// <remarks>

        /// 摘要:

        ///     通过拷贝构造方法,对当前类中的同名变量成员进行实例化。

        /// </remarks>

        /// </summary>

        public RedisCacheManager(AppSettings appSettings, IDistributedCache distributedCache) : base(appSettings,

            distributedCache)

        {

            _connectionWrapper ??=

                new RedisConnectionWrapper(appSettings.Get<DistributedCacheConfig>().ConnectionString);

            _db = _connectionWrapper.GetDatabase();

        }

        #endregion

        #region 方法--私有/保护

        /// <param name="endPoint">Redis分布式缓存数据库软件中所有可用的终结点。</param>

        /// <param name="prefix">1个指定的前缀字符串,默认值:null,即获取所有的Redis缓存键实例。</param>

        /// <summary>

        /// 【获取服务】

        /// <remarks>

        /// 摘要:

        ///     Redis分布式缓存数据库软件所有的分布式缓存数据库(0-15)中,获取与指定前缀字符串相匹配的所有的Redis缓存键实例。

        /// </remarks>

        /// <returns>

        /// 返回:

        ///     与指定前缀字符串相匹配的所有的Redis缓存键实例。

        /// </returns>

        /// </summary>

        protected virtual IEnumerable<RedisKey> GetKeys(EndPoint endPoint, string prefix = null)

        {

            var server = _connectionWrapper.GetServer(endPoint);

            var keys = server.Keys(_db.Database, string.IsNullOrEmpty(prefix) ? null : $"{prefix}*");

            return keys;

        }

        #endregion

        #region 方法

        /// <param name="prefix">1个指定的前缀字符串。</param>

        /// <param name="prefixParameters">数组实例,该实例中存储着n个泛型实例,这些实例为前缀字符串的拼接提供数据支撑。</param>

        /// <summary>

        /// 【异步通过前缀字符串移除实例】

        /// <remarks>

        /// 摘要:

        ///    该方法的覆写方法用于根据1个新的前缀字符串,从缓存数据库中移除1/n个指定的缓存项(/(“JSON”编码格式的)值对)

        /// </remarks>

        /// </summary>

        public override async Task RemoveByPrefixAsync(string prefix, params object[] prefixParameters)

        {

            prefix = PrepareKeyPrefix(prefix, prefixParameters);

            foreach (var endPoint in _connectionWrapper.GetEndPoints())

            {

                var keys = GetKeys(endPoint, prefix);

                _db.KeyDelete(keys.ToArray());

            }

            await RemoveByPrefixInstanceDataAsync(prefix);

        }

        /// <param name="prefix">1个指定的前缀字符串。</param>

        /// <param name="prefixParameters">数组实例,该实例中存储着n个泛型实例,这些实例为前缀字符串的拼接提供数据支撑。</param>

        /// <summary>

        /// 【通过前缀字符串移除实例】

        /// <remarks>

        /// 摘要:

        ///     该方法是抽象方法,该方法的覆写方法用于根据1个新的前缀字符串,从缓存数据库中移除1/n个指定的缓存项(/(“JSON”编码格式的)值对)

        /// </remarks>

        /// </summary>

        public override void RemoveByPrefix(string prefix, params object[] prefixParameters)

        {

            prefix = PrepareKeyPrefix(prefix, prefixParameters);

            foreach (var endPoint in _connectionWrapper.GetEndPoints())

            {

                var keys = GetKeys(endPoint, prefix);

                _db.KeyDelete(keys.ToArray());

            }

            RemoveByPrefixInstanceData(prefix);

        }

        /// <summary>

        /// 【异步清理终结点】

        /// <remarks>

        /// 摘要:

        ///     清理释放Redis分布式缓存数据库软件分布式缓存数据库(0-15)中所有缓存项。

        /// </remarks>

        /// </summary>

        public override async Task ClearAsync()

        {

            await _connectionWrapper.FlushDatabaseAsync();

            ClearInstanceData();

        }

        #endregion

        #region 嵌套类

        /// <summary>

        /// Redis连接封装器--类】

        /// <remarks>

        /// 摘要:

        ///    通过该类中的方法成员实现了调用“StackExchange.Redis”中间件的实例,从而Redis软件对缓存数据的管理操作,这些管理操作包含:缓存数据加载,缓存数据移除和缓存数据清理等。。

        /// </remarks>

        /// </summary>

        protected class RedisConnectionWrapper

        {

            #region 变量--私有/保护

            /// <summary>

            /// 【锁】

            /// <remarks>

            /// 摘要:

            ///     锁实例。

            /// </remarks>

            /// </summary>

            private readonly object _lock = new();

            /// <summary>

            /// 【分布式缓存】

            /// <remarks>

            /// 摘要:

            ///     Redis分布式缓存数据库软件连接器实例,该实例实际上是:“StackExchange.Redis”中间件的实例,通过该实例实现当前程序通过“StackExchange.Redis”中间件的实例与Redis分布式缓存数据库的交互操作。

            /// </remarks>

            /// </summary>

            private volatile ConnectionMultiplexer _connection;

            /// <summary>

            /// 【连接字符串】

            /// <remarks>

            /// 摘要:

            ///    Redis分布式缓存数据库软件的连接字符串。

            /// </remarks>

            /// </summary>

            private readonly Lazy<string> _connectionString;

            #endregion

            #region 构造方法

            /// <param name="connectionString">应用配置类的1个指定实例。</param>

            /// <summary>

            /// 【默认构造方法】

            /// <remarks>

            /// 摘要:

            ///     通过默认构造方法,实例化Redis分布式缓存数据库软件的连接字符串。

            /// </remarks>

            /// </summary>

            public RedisConnectionWrapper(string connectionString)

            {

                _connectionString = new Lazy<string>(connectionString);

            }

            #endregion

            #region 方法----私有/保护

            /// <summary>

            /// 【获取连接】

            /// <remarks>

            /// 摘要:

            ///     建立当前程序与Redis分布式缓存数据库软件的连接。

            /// </remarks>

            /// <returns>

            /// 返回:

            ///     Redis分布式缓存数据库软件的连接器实例。

            /// </returns>

            /// </summary>

            protected ConnectionMultiplexer GetConnection()

            {

                if (_connection != null && _connection.IsConnected)

                    return _connection;

                lock (_lock)

                {

                    if (_connection != null && _connection.IsConnected)

                        return _connection;

                    //显式销毁释放内存中Redis分布式缓存数据库软件的连接器实例,该实例实际上是:显式销毁释放内存中的“StackExchange.Redis”中间件实例。

                    _connection?.Dispose();

                    //实例化Redis分布式缓存数据库软件的连接器实例,该实例实际上是:“StackExchange.Redis”中间件实例。

                    _connection = ConnectionMultiplexer.Connect(_connectionString.Value);

                }

                return _connection;

            }

            #endregion

            #region 方法--销毁

            /// <summary>

            /// 【销毁】

            /// <remarks>

            /// 摘要:

            ///     显式销毁释放内存中的连接器实例,该实例实际上是:显式销毁释放内存中的“StackExchange.Redis”中间件实例。

            /// </remarks>

            /// </summary>

            public void Dispose()

            {

                //显式销毁释放内存中的连接器实例,该实例实际上是:显式销毁释放内存中的“StackExchange.Redis”中间件实例。

                _connection?.Dispose();

            }

            #endregion

            #region 方法

            /// <summary>

            /// 【获取数据库】

            /// <remarks>

            /// 摘要:

            ///     建立当前程序与Redis分布式缓存数据库软件中分布式缓存数据库的连接。

            /// </remarks>

            /// <returns>

            /// 返回:

            ///    数据库连接接口实例,该实例用于建立当前程序与Redis分布式缓存数据库软件中分布式缓存数据库的连接。

            /// </returns>

            /// </summary>

            public IDatabase GetDatabase()

            {

                return GetConnection().GetDatabase();

            }

            /// <param name="endPoint">Redis分布式缓存数据库软件中所有可用的终结点。</param>

            /// <summary>

            /// 【获取服务】

            /// <remarks>

            /// 摘要:

            ///     获取Redis分布式缓存数据库软件中所有可用的终结点,即所有的分布式缓存数据库(0-15)

            /// </remarks>

            /// <returns>

            /// 返回:

            ///     服务接口实例,该实例用于建立当前程序与Redis分布式缓存数据库软件中分布式缓存数据库的连接。

            /// </returns>

            /// </summary>

            public IServer GetServer(EndPoint endPoint)

            {

                return GetConnection().GetServer(endPoint);

            }

            /// <summary>

            /// 【获取终结点】

            /// <remarks>

            /// 摘要:

            ///     获取Redis分布式缓存数据库软件中所有可用的终结点,即所有的分布式缓存数据库(0-15)

            /// </remarks>

            /// <returns>

            /// 返回:

            ///     数组实例,该实例存储着Redis分布式缓存数据库软件中所有可用的终结点,即所有的分布式缓存数据库(0-15)

            /// </returns>

            /// </summary>

            public EndPoint[] GetEndPoints()

            {

                return GetConnection().GetEndPoints();

            }

            /// <summary>

            /// 【异步清理终结点】

            /// <remarks>

            /// 摘要:

            ///     清理释放Redis分布式缓存数据库软件分布式缓存数据库(0-15)中所有缓存项。

            /// </remarks>

            /// </summary>

            public async Task FlushDatabaseAsync()

            {

                var endPoints = GetEndPoints();

                foreach (var endPoint in endPoints)

                    await GetServer(endPoint).FlushDatabaseAsync();

            }

            #endregion

        }

        #endregion

    }

}

2 Srvices.Caching.MemoryDistributedCacheManager

using Microsoft.Extensions.Caching.Distributed;

using Core.Caching;

using Core.Configuration;

namespace Nop.Services.Caching

{

    /// <summary>

    /// Redis分布式缓存委托事件内存管理器--类】

    /// <remarks>

    /// 摘要:

    ///    通过该类中的方法成员实现了把对Redis分布式缓存数据库操作的委托事件存储到一个列表实例(内存)中,从而通过对该列表实例(内存)的操作实现对Redis分布式缓存数据库操作委托事件的集中管理。

    /// </remarks>

    /// </summary>

    public class MemoryDistributedCacheManager : DistributedCacheManager

    {

        #region 变量--私有/保护

        /// <summary>

        /// 【键列表实例】

        /// <remarks>

        /// 摘要:

        ///     1个指定的列表实例,该列表实例(内存)中存储着Redis分布式缓存数据库操作的所有委托事件。

        /// </remarks>

        /// </summary>

        private static readonly List<string> _keysList = new();

        #endregion

        #region 拷贝构造方法

        /// <param name="appSettings">应用配置类的1个指定实例。</param>

        /// <param name="distributedCache">分布式缓存接口实例,该实例实际上是:“StackExchange.Redis”中间件的实例,通过该实例实现当前程序通过“StackExchange.Redis”中间件的实例与Redis分布式缓存数据库的交互操作。</param>

        /// <summary>

        /// 【拷贝构造方法】

        /// <remarks>

        /// 摘要:

        ///     通过拷贝构造方法,把Redis分布式缓存数据库操作的所有委托事件存储到列表实例中或从列表实例中移除。

        /// </remarks>

        /// </summary>

        public MemoryDistributedCacheManager(AppSettings appSettings, IDistributedCache distributedCache) : base(

            appSettings, distributedCache)

        {

            _onKeyAdded += key =>

            {

                using var _ = _locker.Lock();

                if (!_keysList.Contains(key.Key))

                    _keysList.Add(key.Key);

            };

            _onKeyRemoved += key =>

            {

                using var _ = _locker.Lock();

                if (_keysList.Contains(key.Key))

                    _keysList.Remove(key.Key);

            };

        }

        #endregion

        #region 方法

        /// <param name="prefix">1个指定的前缀字符串。</param>

        /// <param name="prefixParameters">数组实例,该实例中存储着n个泛型实例,这些实例为前缀字符串的拼接提供数据支撑。</param>

        /// <summary>

        /// 【异步通过前缀字符串移除实例】

        /// <remarks>

        /// 摘要:

        ///    该方法的覆写方法用于根据1个新的前缀字符串,从缓存数据库中移除1/n个指定的缓存项(/(“JSON”编码格式的)值对)后,并从列表实例中移除相应的Redis分布式缓存数据库操作的委托事件。

        /// </remarks>

        /// </summary>

        public override async Task RemoveByPrefixAsync(string prefix, params object[] prefixParameters)

        {

            using (var _ = _locker.Lock())

            {

                prefix = PrepareKeyPrefix(prefix, prefixParameters);

                //从缓存数据库中移除1/n个指定的缓存项(/(“JSON”编码格式的)值对)后,并从列表实例中移除相应的Redis分布式缓存数据库操作的委托事件。

                foreach (var key in _keysList

                             .Where(key => key.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))

                             .ToList())

                {

                    await _distributedCache.RemoveAsync(key);

                    _keysList.Remove(key);

                }

            }

            await RemoveByPrefixInstanceDataAsync(prefix);

        }

        /// <param name="prefix">1个指定的前缀字符串。</param>

        /// <param name="prefixParameters">数组实例,该实例中存储着n个泛型实例,这些实例为前缀字符串的拼接提供数据支撑。</param>

        /// <summary>

        /// 【通过前缀字符串移除实例】

        /// <remarks>

        /// 摘要:

        ///    该方法的覆写方法用于根据1个新的前缀字符串,从缓存数据库中移除1/n个指定的缓存项(/(“JSON”编码格式的)值对)后,并从列表实例中移除相应的Redis分布式缓存数据库操作的委托事件。

        /// </remarks>

        /// </summary>

        public override void RemoveByPrefix(string prefix, params object[] prefixParameters)

        {

            using (var _ = _locker.Lock())

            {

                prefix = PrepareKeyPrefix(prefix, prefixParameters);

                //从缓存数据库中移除1/n个指定的缓存项(/(“JSON”编码格式的)值对)后,并从列表实例中移除相应的Redis分布式缓存数据库操作的委托事件。

                foreach (var key in _keysList

                             .Where(key => key.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))

                             .ToList())

                {

                    _distributedCache.Remove(key);

                    _keysList.Remove(key);

                }

            }

            RemoveByPrefixInstanceData(prefix);

        }

        /// <summary>

        /// 【异步清理】

        /// <remarks>

        /// 摘要:

        ///    根据列表实例从缓存数据库中移除与其相关的所有缓存项后,清理该列表实例。

        /// </remarks>

        /// </summary>

        public override async Task ClearAsync()

        {

            using (var _ = _locker.Lock())

            {

                //根据列表实例从缓存数据库中移除与其相关的所有缓存项。

                foreach (var key in _keysList)

                    await _distributedCache.RemoveAsync(key);

                //执行列表实例清理操作。

                _keysList.Clear();

            }

            ClearInstanceData();

        }

        #endregion

    }

}

3 重构appsettings.json

{

  "ConnectionStrings": {

    "ConnectionString": "Data Source=.;Initial Catalog=ShopRazor;Integrated Security=False;Persist Security Info=False;User ID=zz;Password=zz;MultipleActiveResultSets=true;Trust Server Certificate=True",

    "DataProvider": "sqlserver",

    "SQLCommandTimeout": null

  },

  "CacheConfig": {

    "DefaultCacheTime": 60,

    "ShortTermCacheTime": 3,

    "BundledFilesCacheTime": 120

  },

  "DistributedCacheConfig": {

    "DistributedCacheType": "redis",

    "Enabled": true,

    "ConnectionString": "127.0.0.1:6379,ssl=False",

    "SchemaName": "dbo",

    "TableName": "DistributedCache"

  }

}

4 重构Program.cs文件

using Core.Configuration;

using Core.Infrastructure;

using Data;

using Data.Configuration;

using Microsoft.EntityFrameworkCore;

using Framework.Infrastructure.Extensions;

using Core.Caching;

using Core.Events;

using Services.Events;

using Nop.Services.Caching;

using Services.Caching;

var builder = WebApplication.CreateBuilder(args);

//如果启动项中不存在“appsettings.json”文件,则通过.Net(Core)的内置方法自动新建“appsettings.json”文件。

builder.Configuration.AddJsonFile("appsettings.json", true, true);

//把当前程序中所有继承了“IConfig”接口的具体实现类的实例,依赖注入到.Net(Core)内置依赖注入容器实例中,如果需要并把这些数据持久化存储到"appsettings.json"文件。

builder.Services.ConfigureApplicationSettings(builder);

builder.Services.AddScoped<INopFileProvider, NopFileProvider>();

var appSettings = Singleton<AppSettings>.Instance;

var distributedCacheConfig = appSettings.Get<DistributedCacheConfig>();

//必须先设定 "Enabled": true,且启动Redis分布式数据库,如果 "Enabled": false,则必须把下面2行给注释掉。

if (!distributedCacheConfig.Enabled)

    return;

switch (distributedCacheConfig.DistributedCacheType)

{

    case DistributedCacheType.Memory:

        builder.Services.AddDistributedMemoryCache();

        break;

    case DistributedCacheType.Redis:

        builder.Services.AddStackExchangeRedisCache(options =>

        {

            options.Configuration = distributedCacheConfig.ConnectionString;

        });

        break;

}

if (distributedCacheConfig.Enabled)

{

    switch (distributedCacheConfig.DistributedCacheType)

    {

        case DistributedCacheType.Memory:

            builder.Services.AddScoped<ILocker, MemoryDistributedCacheManager>();

            builder.Services.AddScoped<IStaticCacheManager, MemoryDistributedCacheManager>();

            break;

        case DistributedCacheType.Redis:

            builder.Services.AddScoped<ILocker, RedisCacheManager>();

            builder.Services.AddScoped<IStaticCacheManager, RedisCacheManager>();

            break;

    }

}

else

{

    builder.Services.AddSingleton<ILocker, MemoryCacheManager>();

    builder.Services.AddSingleton<IStaticCacheManager, MemoryCacheManager>();

}

builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));

builder.Services.AddSingleton<IEventPublisher, EventPublisher>();

var typeFinder = Singleton<ITypeFinder>.Instance;

var consumers = typeFinder.FindClassesOfType(typeof(IConsumer<>)).ToList();

foreach (var consumer in consumers)

    foreach (var findInterface in consumer.FindInterfaces((type, criteria) =>

    {

        var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition());

        return isMatch;

    }, typeof(IConsumer<>)))

        builder.Services.AddScoped(findInterface, consumer);

//注意:在动态对EntityFrameworkCore中间件进行实例化时,必须使用“AddDbContextPool” 内置方法替换“AddDbContext”内置方法,

//否则就会出现异常:“System.InvalidOperationException: The service collection cannot be modified because it is read-only”

builder.Services.AddDbContextPool<EFCoreContext>(options => {

    //从单例实例的字典成员实例中获取当前程序所有配置相关数据。

    AppSettings _appSettings = Singleton<AppSettings>.Instance;

    //从应用配置类实例中获取数据库连接相关数据。

    DataConfig _dataConfig = _appSettings.Get<DataConfig>();

    //说明:如果想要“EntityFrameworkCore”中间件支持多数据库软件,则把选择条件中的所有中间件都注入到依赖注入到.Net(Core)框架内置容器即可,

    //选择条件来限定当前程序只支持所设定的1个数据库软件,当然“DataConfig”类与“appsettings.json”文件也必须为支持多数据库软件进行重构。

    if (_dataConfig.DataProvider.ToString().Equals("sqlserver", StringComparison.InvariantCultureIgnoreCase))

    {

        //通过“DbContextOptionsBuilder”实例中的参数实例,为“Microsoft.EntityFrameworkCore.SqlServer”中间件的实例化提供参数实例,

        //最终把“Microsoft.EntityFrameworkCore.SqlServer”中间件实例,依赖注入到.Net(Core)框架内置容器中。

        //IIS发布部署连接字符串必须使用“SQL Server身份认证数据库连接方式,才能实现发布部署程序与数据库的CURD的操作。

        options.UseSqlServer(_dataConfig.ConnectionString);

    }

});

//通过AddRazorRuntimeCompilation依赖注入中间件实现页面修改热加载(Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation)

builder.Services

    .AddControllersWithViews()

    .AddRazorRuntimeCompilation();

//把具体现类和中间件注入到内置依赖注入容器后,并把.NetCore框架内置依赖注入容器接口实例所存储的当前程序中的具体现类和中间件的实例通过“Engine”(引擎)单例实例存储到单例类的字典属性成员实例中。

//注意:从依赖注入到.Net(Core)框架内置容器中,获取“IServiceProvider”接口实例,必须定义在最后,

//否则“GetServices”/“GetRequiredService”方法将有可能不能获取取1个指定类的实例,因为该类的实例还没有依赖注入到.Net(Core)框架内置容器中。

builder.Services.ConfigureApplicationServices(builder);

var app = builder.Build();

// Configure the HTTP request pipeline.

if (!app.Environment.IsDevelopment())

{

    app.UseExceptionHandler("/Home/Error");

    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.

    app.UseHsts();

}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

/*注意:

    .net7最好不要直接使用app.UseEndpointsapp.UseMvc来集成路由匹配模式,否则会出现:“ASP0014”警告信息,

为了避免该警告信息直接使用最小APIapp.MapControllerRoute来集成路由匹配模式。

 */

app.MapControllerRoute(

        name: "areaRoute",

        pattern: $"{{area:exists}}/{{controller=Install}}/{{action=Index}}/{{id?}}");

//动态实例化EntityFrameworkCore中间件,必须把InstallRefactoring/Index设定为默认启动页面,

//否则依然会因为当前类的拷贝构造方法实例化EntityFrameworkCore中间件是在程序启动前就被实例化的,如果无数据库如果数据库连接字符串,

//那么就会因EntityFrameworkCore中间件实例中不包含数据库如果数据库连接字符串,从而造成上述异常。

app.MapControllerRoute(

      name: "default",

      pattern: "{controller=InstallRefactoring}/{action=Index}/{id?}");

// 通过.NetCore框架的内置管道接口实例,实例化“IServiceProvider”接口实例,同时把继承于“IStartup”所有具体现类中的中间件实例集成到.NetCore框架内置管道中。

app.ConfigureRequestPipeline();

app.Run();

5 运行过程

 

 

 

 

 

 

 

 

 

 

 对以上功能更为具体实现和注释见230510_010ShopRazor(CURD操作与RedisCache缓存的强制清理的实现)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/511029.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

索引 ---MySQL的总结(五)

索引 在mysql数据库之中&#xff0c;如果数据量过大&#xff0c;直接进行遍历会需要使用许多时间。这里使用空间换时间解决这一个问题。 目前就是从解决问题的这一个角度出发&#xff0c;需要增加搜索的速度&#xff0c;一定是要选择好用的数据结构进行搜索&#xff08;遍历的…

第十五届吉林省赛个人题解【中档题(不过可能对你来说是简单题)】(H、G、C)

文章目录 H. Visit the Park(STL)G. Matrix Repair(思维题)C.Random Number Generator(BSGS算法) H. Visit the Park(STL) 题意&#xff1a;给你一个无向图&#xff0c;每条边上都有一个数码&#xff0c;然后给你一个路径&#xff0c;每次你必须从Ai走到Ai1&#xff08;直接走…

【EHub_tx1_tx2_A200】Ubuntu18.04 + ROS_ Melodic + 锐驰LakiBeam 1L单线激光 雷达评测

大家好&#xff0c;我是虎哥&#xff0c;最近这段时间&#xff0c;又手欠入手了锐驰LakiBeam 1L激光雷达&#xff0c;实在是性价比太优秀&#xff0c;话说&#xff0c;最近激光雷达圈确实有点卷。锐驰官网的资料已经很丰富&#xff0c;我这里总结一下自己的简单测试经验&#x…

挑战14天学完Python---

抛弃了数学思维,引入了计算思维,计算思维是抽象和自动化相结合的结果 抽象:抽象问题的形式化逻辑 自动化:将抽象的结果通过程序自动实现 0.1在计算机内部转二进制 0.1转二进制 二进制的0.1与二进制0.2计算 结果再转十进制 在众多编程语言中 ,只有Python语言提供了复数类型.空间…

OpenCL编程指南-1.2OpenCL基本概念

OpenCL概念基础 面向异构平台的应用都必须完成以下步骤&#xff1a; 1&#xff09;发现构成异构系统的组件。 2&#xff09;探查这些组件的特征&#xff0c;使软件能够适应不同硬件单元的特定特性。 3&#xff09;创建将在平台上运行的指令块&#xff08;内核)。 4&#xff09…

紧跟 AI 步伐, Gitee 已支持 AI 模型托管

AI 时代已经来了&#xff01; 现在&#xff0c;越来越多的企业和个人开始使用 AI 技术来解决各种问题。想要了解 AI&#xff0c;那么就一定要了解 AI 模型&#xff0c;作为 AI 的核心技术之一&#xff0c;AI 模型为各种进阶的人工智能应用奠定了基础&#xff0c;从 ChatGPT 、…

Mysql 存储过程+触发器+存储函数+游标

视图&#xff08;view&#xff09; 虚拟存在的表&#xff0c;不保存查询结构&#xff0c;只保存查询的sql逻辑 语法 存储过程 实现定义并存储在数据库的一段sql语句的集合&#xff0c;可减少网络交互&#xff0c;提高性能&#xff0c;代码复用,内容包括&#xff1a;变量&am…

并发编程进阶

并发编程进阶 文章目录 并发编程进阶一、JMM1. JMM的定义&#xff1a;2. 内存屏障&#xff1a; 三. volatile四. as-if-serial五. happens-before六. 缓存一致性&#xff08;Cache coherence&#xff09;7. Synchronized1. synchronized 的使用2. synchronized底层原理 8. Conc…

Web3.0介绍与产业赛道(去中心化,金融与数字资产,应用与存储,区块链技术)

文章目录 1、web3.0时代——区块链技术2、产业赛道&#xff1a;去中心化金融与数字资产3、产业赛道&#xff1a;去中心化应用与存储4、区块链&#xff1a;基础设施与区块链安全和隐私 1、web3.0时代——区块链技术 Web3.0是什么 Web3.0是指下一代互联网技术&#xff0c;它将在…

最优化理论-线性规划的标准形

目录 一、引言 二、线性规划的标准形 1. 线性规划的定义 2. 线性规划的标准形 3. 线性规划的约束条件 三、线性规划的求解方法 1. 单纯形法 2. 内点法 3. 割平面法 四、线性规划的应用 1. 生产计划 2. 运输问题 3. 投资组合问题 五、总结 一、引言 最优化理论是…

数据链路层及其重要协议——以太网

文章目录 数据链路层前言1. 以太网协议2. MTU&#xff08;传输的限制&#xff09;3. ARP协议 数据链路层 前言 以太网&#xff1a; 不是一种具体的网络&#xff0c;而是一种技术标准。既包含了数据链路层的内容&#xff0c;也包含了一些物理层的内容&#xff0c;例如&#xf…

网络层——IP协议详细解读

文章目录 IP协议1. IP协议的报文格式2. IP协议的地址管理3. IP地址的组成4. IP协议的路由选择 IP协议 之前介绍了传输层的重点协议&#xff0c;TCP和UDP协议&#xff0c;以下将介绍网络层的重点协议IP协议。 1. IP协议的报文格式 IP地址 本质上是一个32位整数&#xff0c;在…

华为OD机试真题 Java 实现【不爱施肥的小布】【2023Q2】

一、题目描述 某农村主管理了一大片果园&#xff0c;fields[i]表示不同国林的面积&#xff0c;单位m2&#xff0c;现在要为所有的果林施肥且必须在n天之内完成&#xff0c;否则影响收成。小布是国林的工作人员&#xff0c;他每次选择一片果林进行施肥&#xff0c;且一片国林施…

【Linux初阶】环境变量 | 如何设置、获取环境变量?

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【Linux初阶】 ✒️✒️本篇内容&#xff1a;讨论为什么指令作为一个可执行程序不需要加 ./运行&#xff1b;环境变量为什么会自己恢复&#xff1b;环境变量…

Acwing456. 车站分级

一条单向的铁路线上&#xff0c;依次有编号为 1, 2, …, n的 n 个火车站。 每个火车站都有一个级别&#xff0c;最低为 1 级。 现有若干趟车次在这条线路上行驶&#xff0c;每一趟都满足如下要求&#xff1a;如果这趟车次停靠了火车站 xx&#xff0c;则始发站、终点站之间…

【网络】-- 数据链路层

应用层&#xff08;http、https&#xff09;&#xff1a; 数据的使用。传输层&#xff08;UDP、TCP&#xff09;&#xff1a;网络通讯的细节&#xff0c;将数据可靠的从A主机跨网络送到B主机。网络层&#xff08;IP&#xff09;&#xff1a;提供一种能力&#xff0c;将数据从A主…

Real-ESRGAN:Training Real-World Blind Super-Resolution with Pure Synthetic Data

https://github.com/NightmareAI/Real-ESRGAN/tree/masterhttps://github.com/NightmareAI/Real-ESRGAN/tree/master从SRCNN到EDSR&#xff0c;总结深度学习端到端超分辨率方法发展历程 - 知乎超分辨率技术&#xff08;Super-Resolution, SR&#xff09;是指从观测到的低分辨率…

设计模式MVC、MVP、MVVM

MVC、MVP和MVVM是什么&#xff1f; MVC&#xff1a;Model-View-Controller&#xff0c;是一种分层解偶的框架&#xff0c;Model层提供本地数据和网络请求&#xff0c;View层处理视图&#xff0c;Controller处理逻辑&#xff0c;存在问题是Controller层和View层的划分不明显&am…

SpringBoot+@Validate+全局异常拦截实现自定义规则参数校验(校验get请求参数不能为空且在指定枚举类型中)

场景 SpringBootValidated实现参数验证(非空、类型、范围、格式等)-若依前后端导入Excel数据并校验为例&#xff1a; SpringBootValidated实现参数验证(非空、类型、范围、格式等)-若依前后端导入Excel数据并校验为例_validated 怎么设置boolean类型非空_霸道流氓气质的博客-…

Elasticsearch02

目录 Elasticsearch02DSL查询文档查询所有全文检索查询精确查询地理查询复合查询 搜索结果处理排序分页高亮 DSL总结RestClient查询文档快速入门:match_all查询match查询精确查询布尔查询排序、分页高亮 实战案例HotelControllerIHotelServiceHotelMapperHotelHotelDocPageResu…