首页 > 其他分享 >ABP - 缓存模块(2)

ABP - 缓存模块(2)

时间:2023-06-27 13:11:07浏览次数:35  
标签:缓存 模块 cache value hideErrors ABP item key null

1. 缓存模块源码解析

个人觉得 ABP 分布式缓存模块有三个值得关注的核心点。首先是 AbpRedisCache 类继承了微软原生的 RedisCache,并 通过反射的方式获取RedisCache的私有方法对 RedisCache 进行扩展,实现了 ABP 分布式缓存中的批量操作方法。

image

为什么要这么做呢?因为基于 Redis 缓存的批量操作需要使用到 StackExchange.Redis 原生的SDK,而且在进行操作前总需要先进行 Redis 连接,而相应的方法和属性原生的 RedisCache 中都有,但是都是私有(private)的,在继承类中也无法使用,所以使用反射的方式提取出相应的方法和属性,以便在继承类中复用。这也是对于类功能进行继承扩展的时候的一种很有用的方式。

image

image

第二点是 ABP 缓存模块通过 IDistributedCache<CacheItem, CacheKey> 接口扩展了原生的 IDistributedCache 接口的功能,而在具体实现上是将原有的 IDistributedCache 服务注入进行复用相应功能的,并在前后增加额外的逻辑对功能进行扩展增强,实际上就是适配器模式。

image

image

而最常使用的 IDistributedCache<CacheItem> 接口,以前其实现类是直接继承 DistributedCache<CacheItem, CacheKey> 的,现在改成了直接用适配器模式。

image

最后一个是缓存的事务性,通过工作单元使缓存和其他事务操作保持原子性,避免缓存已经更新而其他事务失败回滚导致数据不一致的问题。实际上就是先不真正地更新缓存,而是将缓存数据通过字典保存在工作单元中,保证一个工作单元内拿到的缓存数据是最新的,同时注册工作单元提交事件,在工作单元正在提交成功的时候才执行真正更新缓存的逻辑。

image

工作单元相关的内容就后面再在专门的章节讲吧,这部分的内容比较复杂,一时半会比较难讲清。

2. 自己扩展的 IDistributedCache

ABP 框架扩展的 IDistributedCache 泛型接口在内部帮我们处理实例对象进行序列化/反序列化以及转码为 byte 数组的问题,大大提升了我们使用分布式缓存的方便性,但也存在一些问题。

  • 它是基于类的泛型,如果我们在一个服务中需要使用多个缓存类型的话,我们就得注入多个的泛型接口,还是有些不方便的
  • 它的缓存键是以默认是以泛型类型的全类名作为前缀,虽然我们可以通过特性指定类型名称,但是对于集合,缓存键就很不清晰了
    由于这些情况的存在,也基于我们在日常开发中的使用习惯,我在工作中又基于 ABP 的 IDistributedCache<CacheItem> 接口进行扩展。内部实现基本一致,主要就是将基于类的泛型,改成基于方法的泛型,并且提供自己的 IDistributedCacheKeyNormalizer 实现类,将缓存键的设置规则交给了缓存存取时进行设置。 代码如下:
public interface IWantDistributedCache
{
	/// <summary>
	/// Gets a cache item with the given key. If no cache item is found for the given key then returns null.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <returns>The cache item, or null.</returns>
	TCacheItem Get<TCacheItem, TCacheKey>(
		TCacheKey key,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false
	) where TCacheItem : class;

	/// <summary>
	/// Gets multiple cache items with the given keys.
	///
	/// The returned list contains exactly the same count of items specified in the given keys.
	/// An item in the return list can not be null, but an item in the list has null value
	/// if the related key not found in the cache.
	/// </summary>
	/// <param name="keys">The keys of cached items to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <returns>List of cache items.</returns>
	KeyValuePair<TCacheKey, TCacheItem>[] GetMany<TCacheItem, TCacheKey>(
		IEnumerable<TCacheKey> keys,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false
	) where TCacheItem : class;

	/// <summary>
	/// Gets multiple cache items with the given keys.
	///
	/// The returned list contains exactly the same count of items specified in the given keys.
	/// An item in the return list can not be null, but an item in the list has null value
	/// if the related key not found in the cache.
	///
	/// </summary>
	/// <param name="keys">The keys of cached items to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// /// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>List of cache items.</returns>
	Task<KeyValuePair<TCacheKey, TCacheItem>[]> GetManyAsync<TCacheItem, TCacheKey>(
		IEnumerable<TCacheKey> keys,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default
	) where TCacheItem : class;

	/// <summary>
	/// Gets a cache item with the given key. If no cache item is found for the given key then returns null.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>The cache item, or null.</returns>
	Task<TCacheItem> GetAsync<TCacheItem, TCacheKey>(
		[NotNull] TCacheKey key,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default
	) where TCacheItem : class;

	/// <summary>
	/// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item
	/// provided by <paramref name="factory" /> delegate and returns the provided cache item.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="factory">The factory delegate is used to provide the cache item when no cache item is found for the given <paramref name="key" />.</param>
	/// <param name="optionsFactory">The cache options for the factory delegate.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <returns>The cache item.</returns>
	TCacheItem GetOrAdd<TCacheItem, TCacheKey>(
		TCacheKey key,
		Func<TCacheItem> factory,
		string cacheName,
		Func<DistributedCacheEntryOptions> optionsFactory = null,
		bool? hideErrors = null,
		bool considerUow = false
	) where TCacheItem : class;

	/// <summary>
	/// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item
	/// provided by <paramref name="factory" /> delegate and returns the provided cache item.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="factory">The factory delegate is used to provide the cache item when no cache item is found for the given <paramref name="key" />.</param>
	/// <param name="optionsFactory">The cache options for the factory delegate.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>The cache item.</returns>
	Task<TCacheItem> GetOrAddAsync<TCacheItem, TCacheKey>(
		[NotNull] TCacheKey key,
		Func<Task<TCacheItem>> factory,
		string cacheName,
		Func<DistributedCacheEntryOptions> optionsFactory = null,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default
	) where TCacheItem : class;

	/// <summary>
	/// Sets the cache item value for the provided key.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="value">The cache item value to set in the cache.</param>
	/// <param name="options">The cache options for the value.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	void Set<TCacheItem, TCacheKey>(
		TCacheKey key,
		TCacheItem value,
		string cacheName,
		DistributedCacheEntryOptions options = null,
		bool? hideErrors = null,
		bool considerUow = false
	) where TCacheItem : class;

	/// <summary>
	/// Sets the cache item value for the provided key.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="value">The cache item value to set in the cache.</param>
	/// <param name="options">The cache options for the value.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
	Task SetAsync<TCacheItem, TCacheKey>(
		[NotNull] TCacheKey key,
		[NotNull] TCacheItem value,
		string cacheName,
		[CanBeNull] DistributedCacheEntryOptions options = null,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default
	) where TCacheItem : class;

	/// <summary>
	/// Sets multiple cache items.
	/// Based on the implementation, this can be more efficient than setting multiple items individually.
	/// </summary>
	/// <param name="items">Items to set on the cache</param>
	/// <param name="options">The cache options for the value.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	void SetMany<TCacheItem, TCacheKey>(
		IEnumerable<KeyValuePair<TCacheKey, TCacheItem>> items,
		string cacheName,
		DistributedCacheEntryOptions options = null,
		bool? hideErrors = null,
		bool considerUow = false
	) where TCacheItem : class;

	/// <summary>
	/// Sets multiple cache items.
	/// Based on the implementation, this can be more efficient than setting multiple items individually.
	/// </summary>
	/// <param name="items">Items to set on the cache</param>
	/// <param name="options">The cache options for the value.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
	Task SetManyAsync<TCacheItem, TCacheKey>(
		IEnumerable<KeyValuePair<TCacheKey, TCacheItem>> items,
		string cacheName,
		DistributedCacheEntryOptions options = null,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default
	) where TCacheItem : class;

	/// <summary>
	/// Refreshes the cache value of the given key, and resets its sliding expiration timeout.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	void Refresh<TCacheKey>(
		TCacheKey key,
		string cacheName,
		bool? hideErrors = null
	);

	/// <summary>
	/// Refreshes the cache value of the given key, and resets its sliding expiration timeout.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
	Task RefreshAsync<TCacheKey>(
		TCacheKey key,
		string cacheName,
		bool? hideErrors = null,
		CancellationToken token = default
	);

	/// <summary>
	/// Removes the cache item for given key from cache.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	void Remove<TCacheItem, TCacheKey>(
		TCacheKey key,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false
	) where TCacheItem : class;

	/// <summary>
	/// Removes the cache item for given key from cache.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
	Task RemoveAsync<TCacheItem, TCacheKey>(
		TCacheKey key,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default
	) where TCacheItem : class;
}

public class WantDistributedCache : IWantDistributedCache
{
	public const string UowCacheName = "WantDistributedCache";

	public ILogger<WantDistributedCache> Logger { get; set; }

	protected string CacheName { get; set; }

	protected bool IgnoreMultiTenancy { get; set; }

	protected IDistributedCache Cache { get; }

	protected ICancellationTokenProvider CancellationTokenProvider { get; }

	protected IDistributedCacheSerializer Serializer { get; }

	protected IDistributedCacheKeyNormalizer KeyNormalizer { get; }

	protected IHybridServiceScopeFactory ServiceScopeFactory { get; }

	protected IUnitOfWorkManager UnitOfWorkManager { get; }

	protected SemaphoreSlim SyncSemaphore { get; }

	protected DistributedCacheEntryOptions DefaultCacheOptions;

	private readonly AbpDistributedCacheOptions _distributedCacheOption;

	public WantDistributedCache(
		IOptions<AbpDistributedCacheOptions> distributedCacheOption,
		IDistributedCache cache,
		ICancellationTokenProvider cancellationTokenProvider,
		IDistributedCacheSerializer serializer,
		IDistributedCacheKeyNormalizer keyNormalizer,
		IHybridServiceScopeFactory serviceScopeFactory,
		IUnitOfWorkManager unitOfWorkManager)
	{
		_distributedCacheOption = distributedCacheOption.Value;
		Cache = cache;
		CancellationTokenProvider = cancellationTokenProvider;
		Logger = NullLogger<WantDistributedCache>.Instance;
		Serializer = serializer;
		KeyNormalizer = keyNormalizer;
		ServiceScopeFactory = serviceScopeFactory;
		UnitOfWorkManager = unitOfWorkManager;

		SyncSemaphore = new SemaphoreSlim(1, 1);

		SetDefaultOptions();
	}

	protected virtual string NormalizeKey<TCacheKey>(TCacheKey key, string cacheName)
	{
		return KeyNormalizer.NormalizeKey(
			new DistributedCacheKeyNormalizeArgs(
				key.ToString(),
				cacheName,
				IgnoreMultiTenancy
			)
		);
	}

	protected virtual DistributedCacheEntryOptions GetDefaultCacheEntryOptions()
	{
		foreach (var configure in _distributedCacheOption.CacheConfigurators)
		{
			var options = configure.Invoke(CacheName);
			if (options != null)
			{
				return options;
			}
		}

		return _distributedCacheOption.GlobalCacheEntryOptions;
	}

	protected virtual void SetDefaultOptions()
	{
		//CacheName = CacheNameAttribute.GetCacheName(typeof(TCacheItem));

		////IgnoreMultiTenancy
		//IgnoreMultiTenancy = typeof(TCacheItem).IsDefined(typeof(IgnoreMultiTenancyAttribute), true);

		//Configure default cache entry options
		DefaultCacheOptions = GetDefaultCacheEntryOptions();
	}

	/// <summary>
	/// Gets a cache item with the given key. If no cache item is found for the given key then returns null.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <returns>The cache item, or null.</returns>
	public virtual TCacheItem Get<TCacheItem, TCacheKey>(
		TCacheKey key,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false) where TCacheItem : class
	{
		hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

		if (ShouldConsiderUow(considerUow))
		{
			var value = GetUnitOfWorkCache<TCacheItem, TCacheKey>().GetOrDefault(key)?.GetUnRemovedValueOrNull();
			if (value != null)
			{
				return value;
			}
		}

		byte[] cachedBytes;

		try
		{
			cachedBytes = Cache.Get(NormalizeKey(key, cacheName));
		}
		catch (Exception ex)
		{
			if (hideErrors == true)
			{
				HandleException(ex);
				return null;
			}

			throw;
		}

		return ToCacheItem<TCacheItem>(cachedBytes);
	}

	public virtual KeyValuePair<TCacheKey, TCacheItem>[] GetMany<TCacheItem, TCacheKey>(
		IEnumerable<TCacheKey> keys,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false) where TCacheItem : class
	{
		var keyArray = keys.ToArray();

		var cacheSupportsMultipleItems = Cache as ICacheSupportsMultipleItems;
		if (cacheSupportsMultipleItems == null)
		{
			return GetManyFallback<TCacheItem, TCacheKey>(
				keyArray,
				cacheName,
				hideErrors,
				considerUow
			);
		}

		var notCachedKeys = new List<TCacheKey>();
		var cachedValues = new List<KeyValuePair<TCacheKey, TCacheItem>>();
		if (ShouldConsiderUow(considerUow))
		{
			var uowCache = GetUnitOfWorkCache<TCacheItem, TCacheKey>();
			foreach (var key in keyArray)
			{
				var value = uowCache.GetOrDefault(key)?.GetUnRemovedValueOrNull();
				if (value != null)
				{
					cachedValues.Add(new KeyValuePair<TCacheKey, TCacheItem>(key, value));
				}
			}

			notCachedKeys = keyArray.Except(cachedValues.Select(x => x.Key)).ToList();
			if (!notCachedKeys.Any())
			{
				return cachedValues.ToArray();
			}
		}

		hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
		byte[][] cachedBytes;

		var readKeys = notCachedKeys.Any() ? notCachedKeys.ToArray() : keyArray;
		try
		{
			cachedBytes = cacheSupportsMultipleItems.GetMany(readKeys.Select(key => NormalizeKey(key, cacheName)));
		}
		catch (Exception ex)
		{
			if (hideErrors == true)
			{
				HandleException(ex);
				return ToCacheItemsWithDefaultValues<TCacheItem, TCacheKey>(keyArray);
			}

			throw;
		}

		return cachedValues.Concat(ToCacheItems<TCacheItem, TCacheKey>(cachedBytes, readKeys)).ToArray();
	}

	protected virtual KeyValuePair<TCacheKey, TCacheItem>[] GetManyFallback<TCacheItem, TCacheKey>(
		TCacheKey[] keys,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false) where TCacheItem : class
	{
		hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

		try
		{
			return keys
				.Select(key => new KeyValuePair<TCacheKey, TCacheItem>(
						key,
						Get<TCacheItem, TCacheKey>(key, cacheName, false, considerUow)
					)
				).ToArray();
		}
		catch (Exception ex)
		{
			if (hideErrors == true)
			{
				HandleException(ex);
				return ToCacheItemsWithDefaultValues<TCacheItem, TCacheKey>(keys);
			}

			throw;
		}
	}

	public virtual async Task<KeyValuePair<TCacheKey, TCacheItem>[]> GetManyAsync<TCacheItem, TCacheKey>(
		IEnumerable<TCacheKey> keys,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default) where TCacheItem : class
	{
		var keyArray = keys.ToArray();

		var cacheSupportsMultipleItems = Cache as ICacheSupportsMultipleItems;
		if (cacheSupportsMultipleItems == null)
		{
			return await GetManyFallbackAsync<TCacheItem, TCacheKey>(
				keyArray,
				cacheName,
				hideErrors,
				considerUow,
				token
			);
		}

		var notCachedKeys = new List<TCacheKey>();
		var cachedValues = new List<KeyValuePair<TCacheKey, TCacheItem>>();
		if (ShouldConsiderUow(considerUow))
		{
			var uowCache = GetUnitOfWorkCache<TCacheItem, TCacheKey>();
			foreach (var key in keyArray)
			{
				var value = uowCache.GetOrDefault(key)?.GetUnRemovedValueOrNull();
				if (value != null)
				{
					cachedValues.Add(new KeyValuePair<TCacheKey, TCacheItem>(key, value));
				}
			}

			notCachedKeys = keyArray.Except(cachedValues.Select(x => x.Key)).ToList();
			if (!notCachedKeys.Any())
			{
				return cachedValues.ToArray();
			}
		}

		hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;
		byte[][] cachedBytes;

		var readKeys = notCachedKeys.Any() ? notCachedKeys.ToArray() : keyArray;

		try
		{
			cachedBytes = await cacheSupportsMultipleItems.GetManyAsync(
				readKeys.Select(key => NormalizeKey(key, cacheName)),
				CancellationTokenProvider.FallbackToProvider(token)
			);
		}
		catch (Exception ex)
		{
			if (hideErrors == true)
			{
				await HandleExceptionAsync(ex);
				return ToCacheItemsWithDefaultValues<TCacheItem, TCacheKey>(keyArray);
			}

			throw;
		}

		return cachedValues.Concat(ToCacheItems<TCacheItem, TCacheKey>(cachedBytes, readKeys)).ToArray();
	}

	protected virtual async Task<KeyValuePair<TCacheKey, TCacheItem>[]> GetManyFallbackAsync<TCacheItem, TCacheKey>(
		TCacheKey[] keys,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default) where TCacheItem : class
	{
		hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

		try
		{
			var result = new List<KeyValuePair<TCacheKey, TCacheItem>>();

			foreach (var key in keys)
			{
				result.Add(new KeyValuePair<TCacheKey, TCacheItem>(
					key,
					await GetAsync<TCacheItem, TCacheKey>(key, cacheName, false, considerUow, token: token))
				);
			}

			return result.ToArray();
		}
		catch (Exception ex)
		{
			if (hideErrors == true)
			{
				await HandleExceptionAsync(ex);
				return ToCacheItemsWithDefaultValues<TCacheItem, TCacheKey>(keys);
			}

			throw;
		}
	}

	/// <summary>
	/// Gets a cache item with the given key. If no cache item is found for the given key then returns null.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>The cache item, or null.</returns>
	public virtual async Task<TCacheItem> GetAsync<TCacheItem, TCacheKey>(
		TCacheKey key,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default) where TCacheItem : class
	{
		hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

		if (ShouldConsiderUow(considerUow))
		{
			var value = GetUnitOfWorkCache<TCacheItem, TCacheKey>().GetOrDefault(key)?.GetUnRemovedValueOrNull();
			if (value != null)
			{
				return value;
			}
		}

		byte[] cachedBytes;

		try
		{
			cachedBytes = await Cache.GetAsync(
				NormalizeKey(key, cacheName),
				CancellationTokenProvider.FallbackToProvider(token)
			);
		}
		catch (Exception ex)
		{
			if (hideErrors == true)
			{
				await HandleExceptionAsync(ex);
				return null;
			}

			throw;
		}

		if (cachedBytes == null)
		{
			return null;
		}

		return Serializer.Deserialize<TCacheItem>(cachedBytes);
	}

	/// <summary>
	/// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item
	/// provided by <paramref name="factory" /> delegate and returns the provided cache item.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="factory">The factory delegate is used to provide the cache item when no cache item is found for the given <paramref name="key" />.</param>
	/// <param name="optionsFactory">The cache options for the factory delegate.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <returns>The cache item.</returns>
	public virtual TCacheItem GetOrAdd<TCacheItem, TCacheKey>(
		TCacheKey key,
		Func<TCacheItem> factory,
		string cacheName,
		Func<DistributedCacheEntryOptions> optionsFactory = null,
		bool? hideErrors = null,
		bool considerUow = false) where TCacheItem : class
	{
		var value = Get<TCacheItem, TCacheKey>(key, cacheName, hideErrors, considerUow);
		if (value != null)
		{
			return value;
		}

		using (SyncSemaphore.Lock())
		{
			value = Get<TCacheItem, TCacheKey>(key, cacheName, hideErrors, considerUow);
			if (value != null)
			{
				return value;
			}

			value = factory();

			if (ShouldConsiderUow(considerUow))
			{
				var uowCache = GetUnitOfWorkCache<TCacheItem, TCacheKey>();
				if (uowCache.TryGetValue(key, out var item))
				{
					item.SetValue(value);
				}
				else
				{
					uowCache.Add(key, new UnitOfWorkCacheItem<TCacheItem>(value));
				}
			}

			Set(key, value, cacheName, optionsFactory?.Invoke(), hideErrors, considerUow);
		}

		return value;
	}

	/// <summary>
	/// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item
	/// provided by <paramref name="factory" /> delegate and returns the provided cache item.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="factory">The factory delegate is used to provide the cache item when no cache item is found for the given <paramref name="key" />.</param>
	/// <param name="optionsFactory">The cache options for the factory delegate.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>The cache item.</returns>
	public virtual async Task<TCacheItem> GetOrAddAsync<TCacheItem, TCacheKey>(
		TCacheKey key,
		Func<Task<TCacheItem>> factory,
		string cacheName,
		Func<DistributedCacheEntryOptions> optionsFactory = null,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default) where TCacheItem : class
	{
		token = CancellationTokenProvider.FallbackToProvider(token);
		var value = await GetAsync<TCacheItem, TCacheKey>(key, cacheName, hideErrors, considerUow, token);
		if (value != null)
		{
			return value;
		}

		using (await SyncSemaphore.LockAsync(token))
		{
			value = await GetAsync<TCacheItem, TCacheKey>(key, cacheName, hideErrors, considerUow, token);
			if (value != null)
			{
				return value;
			}

			value = await factory();

			if (ShouldConsiderUow(considerUow))
			{
				var uowCache = GetUnitOfWorkCache<TCacheItem, TCacheKey>();
				if (uowCache.TryGetValue(key, out var item))
				{
					item.SetValue(value);
				}
				else
				{
					uowCache.Add(key, new UnitOfWorkCacheItem<TCacheItem>(value));
				}
			}

			await SetAsync(key, value, cacheName, optionsFactory?.Invoke(), hideErrors, considerUow, token);
		}

		return value;
	}

	/// <summary>
	/// Sets the cache item value for the provided key.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="value">The cache item value to set in the cache.</param>
	/// <param name="options">The cache options for the value.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	public virtual void Set<TCacheItem, TCacheKey>(
		TCacheKey key,
		TCacheItem value,
		string cacheName,
		DistributedCacheEntryOptions options = null,
		bool? hideErrors = null,
		bool considerUow = false) where TCacheItem : class
	{
		void SetRealCache()
		{
			hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

			try
			{
				Cache.Set(
					NormalizeKey(key, cacheName),
					Serializer.Serialize(value),
					options ?? DefaultCacheOptions
				);
			}
			catch (Exception ex)
			{
				if (hideErrors == true)
				{
					HandleException(ex);
					return;
				}

				throw;
			}
		}

		if (ShouldConsiderUow(considerUow))
		{
			var uowCache = GetUnitOfWorkCache<TCacheItem, TCacheKey>();
			if (uowCache.TryGetValue(key, out _))
			{
				uowCache[key].SetValue(value);
			}
			else
			{
				uowCache.Add(key, new UnitOfWorkCacheItem<TCacheItem>(value));
			}

			// ReSharper disable once PossibleNullReferenceException
			UnitOfWorkManager.Current.OnCompleted(() =>
			{
				SetRealCache();
				return Task.CompletedTask;
			});
		}
		else
		{
			SetRealCache();
		}
	}
	/// <summary>
	/// Sets the cache item value for the provided key.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="value">The cache item value to set in the cache.</param>
	/// <param name="options">The cache options for the value.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
	public virtual async Task SetAsync<TCacheItem, TCacheKey>(
		TCacheKey key,
		TCacheItem value,
		string cacheName,
		DistributedCacheEntryOptions options = null,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default) where TCacheItem : class
	{
		async Task SetRealCache()
		{
			hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

			try
			{
				await Cache.SetAsync(
					NormalizeKey(key, cacheName),
					Serializer.Serialize(value),
					options ?? DefaultCacheOptions,
					CancellationTokenProvider.FallbackToProvider(token)
				);
			}
			catch (Exception ex)
			{
				if (hideErrors == true)
				{
					await HandleExceptionAsync(ex);
					return;
				}

				throw;
			}
		}

		if (ShouldConsiderUow(considerUow))
		{
			var uowCache = GetUnitOfWorkCache<TCacheItem, TCacheKey>();
			if (uowCache.TryGetValue(key, out _))
			{
				uowCache[key].SetValue(value);
			}
			else
			{
				uowCache.Add(key, new UnitOfWorkCacheItem<TCacheItem>(value));
			}

			// ReSharper disable once PossibleNullReferenceException
			UnitOfWorkManager.Current.OnCompleted(SetRealCache);
		}
		else
		{
			await SetRealCache();
		}
	}

	public void SetMany<TCacheItem, TCacheKey>(
		IEnumerable<KeyValuePair<TCacheKey, TCacheItem>> items,
		string cacheName,
		DistributedCacheEntryOptions options = null,
		bool? hideErrors = null,
		bool considerUow = false) where TCacheItem : class
	{
		var itemsArray = items.ToArray();

		var cacheSupportsMultipleItems = Cache as ICacheSupportsMultipleItems;
		if (cacheSupportsMultipleItems == null)
		{
			SetManyFallback(
				itemsArray,
				cacheName,
				options,
				hideErrors,
				considerUow
			);

			return;
		}

		void SetRealCache()
		{
			hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

			try
			{
				cacheSupportsMultipleItems.SetMany(
					ToRawCacheItems(itemsArray, cacheName),
					options ?? DefaultCacheOptions
				);
			}
			catch (Exception ex)
			{
				if (hideErrors == true)
				{
					HandleException(ex);
					return;
				}

				throw;
			}
		}

		if (ShouldConsiderUow(considerUow))
		{
			var uowCache = GetUnitOfWorkCache<TCacheItem, TCacheKey>();

			foreach (var pair in itemsArray)
			{
				if (uowCache.TryGetValue(pair.Key, out _))
				{
					uowCache[pair.Key].SetValue(pair.Value);
				}
				else
				{
					uowCache.Add(pair.Key, new UnitOfWorkCacheItem<TCacheItem>(pair.Value));
				}
			}

			// ReSharper disable once PossibleNullReferenceException
			UnitOfWorkManager.Current.OnCompleted(() =>
			{
				SetRealCache();
				return Task.CompletedTask;
			});
		}
		else
		{
			SetRealCache();
		}
	}

	protected virtual void SetManyFallback<TCacheItem, TCacheKey>(
		KeyValuePair<TCacheKey, TCacheItem>[] items,
		string cacheName,
		DistributedCacheEntryOptions options = null,
		bool? hideErrors = null,
		bool considerUow = false) where TCacheItem : class
	{
		hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

		try
		{
			foreach (var item in items)
			{
				Set(
					item.Key,
					item.Value,
					cacheName,
					options,
					false,
					considerUow
				);
			}
		}
		catch (Exception ex)
		{
			if (hideErrors == true)
			{
				HandleException(ex);
				return;
			}

			throw;
		}
	}

	public virtual async Task SetManyAsync<TCacheItem, TCacheKey>(
		IEnumerable<KeyValuePair<TCacheKey, TCacheItem>> items,
		string cacheName,
		DistributedCacheEntryOptions options = null,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default) where TCacheItem : class
	{
		var itemsArray = items.ToArray();

		var cacheSupportsMultipleItems = Cache as ICacheSupportsMultipleItems;
		if (cacheSupportsMultipleItems == null)
		{
			await SetManyFallbackAsync(
				itemsArray,
				cacheName,
				options,
				hideErrors,
				considerUow,
				token
			);

			return;
		}

		async Task SetRealCache()
		{
			hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

			try
			{
				await cacheSupportsMultipleItems.SetManyAsync(
					ToRawCacheItems(itemsArray, cacheName),
					options ?? DefaultCacheOptions,
					CancellationTokenProvider.FallbackToProvider(token)
				);
			}
			catch (Exception ex)
			{
				if (hideErrors == true)
				{
					await HandleExceptionAsync(ex);
					return;
				}

				throw;
			}
		}

		if (ShouldConsiderUow(considerUow))
		{
			var uowCache = GetUnitOfWorkCache<TCacheItem, TCacheKey>();

			foreach (var pair in itemsArray)
			{
				if (uowCache.TryGetValue(pair.Key, out _))
				{
					uowCache[pair.Key].SetValue(pair.Value);
				}
				else
				{
					uowCache.Add(pair.Key, new UnitOfWorkCacheItem<TCacheItem>(pair.Value));
				}
			}

			// ReSharper disable once PossibleNullReferenceException
			UnitOfWorkManager.Current.OnCompleted(SetRealCache);
		}
		else
		{
			await SetRealCache();
		}
	}

	protected virtual async Task SetManyFallbackAsync<TCacheItem, TCacheKey>(
		KeyValuePair<TCacheKey, TCacheItem>[] items,
		string cacheName,
		DistributedCacheEntryOptions options = null,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default) where TCacheItem : class
	{
		hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

		try
		{
			foreach (var item in items)
			{
				await SetAsync(
					item.Key,
					item.Value,
					cacheName,
					options,
					false,
					considerUow,
					token: token
				);
			}
		}
		catch (Exception ex)
		{
			if (hideErrors == true)
			{
				await HandleExceptionAsync(ex);
				return;
			}

			throw;
		}
	}

	/// <summary>
	/// Refreshes the cache value of the given key, and resets its sliding expiration timeout.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	public virtual void Refresh<TCacheKey>(
		TCacheKey key,
		string cacheName,
		bool? hideErrors = null)
	{
		hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

		try
		{
			Cache.Refresh(NormalizeKey(key, cacheName));
		}
		catch (Exception ex)
		{
			if (hideErrors == true)
			{
				HandleException(ex);
				return;
			}

			throw;
		}
	}

	/// <summary>
	/// Refreshes the cache value of the given key, and resets its sliding expiration timeout.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
	public virtual async Task RefreshAsync<TCacheKey>(
		TCacheKey key,
		string cacheName,
		bool? hideErrors = null,
		CancellationToken token = default)
	{
		hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

		try
		{
			await Cache.RefreshAsync(NormalizeKey(key, cacheName), CancellationTokenProvider.FallbackToProvider(token));
		}
		catch (Exception ex)
		{
			if (hideErrors == true)
			{
				await HandleExceptionAsync(ex);
				return;
			}

			throw;
		}
	}

	/// <summary>
	/// Removes the cache item for given key from cache.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	public virtual void Remove<TCacheItem, TCacheKey>(
		TCacheKey key,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false) where TCacheItem : class
	{
		void RemoveRealCache()
		{
			hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

			try
			{
				Cache.Remove(NormalizeKey(key, cacheName));
			}
			catch (Exception ex)
			{
				if (hideErrors == true)
				{
					HandleException(ex);
					return;
				}

				throw;
			}
		}

		if (ShouldConsiderUow(considerUow))
		{
			var uowCache = GetUnitOfWorkCache<TCacheItem, TCacheKey>();
			if (uowCache.TryGetValue(key, out _))
			{
				uowCache[key].RemoveValue();
			}

			// ReSharper disable once PossibleNullReferenceException
			UnitOfWorkManager.Current.OnCompleted(() =>
			{
				RemoveRealCache();
				return Task.CompletedTask;
			});
		}
		else
		{
			RemoveRealCache();
		}
	}

	/// <summary>
	/// Removes the cache item for given key from cache.
	/// </summary>
	/// <param name="key">The key of cached item to be retrieved from the cache.</param>
	/// <param name="hideErrors">Indicates to throw or hide the exceptions for the distributed cache.</param>
	/// <param name="considerUow">This will store the cache in the current unit of work until the end of the current unit of work does not really affect the cache.</param>
	/// <param name="token">The <see cref="T:System.Threading.CancellationToken" /> for the task.</param>
	/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> indicating that the operation is asynchronous.</returns>
	public virtual async Task RemoveAsync<TCacheItem, TCacheKey>(
		TCacheKey key,
		string cacheName,
		bool? hideErrors = null,
		bool considerUow = false,
		CancellationToken token = default) where TCacheItem : class
	{
		async Task RemoveRealCache()
		{
			hideErrors = hideErrors ?? _distributedCacheOption.HideErrors;

			try
			{
				await Cache.RemoveAsync(NormalizeKey(key, cacheName), CancellationTokenProvider.FallbackToProvider(token));
			}
			catch (Exception ex)
			{
				if (hideErrors == true)
				{
					await HandleExceptionAsync(ex);
					return;
				}

				throw;
			}
		}

		if (ShouldConsiderUow(considerUow))
		{
			var uowCache = GetUnitOfWorkCache<TCacheItem, TCacheKey>();
			if (uowCache.TryGetValue(key, out _))
			{
				uowCache[key].RemoveValue();
			}

			// ReSharper disable once PossibleNullReferenceException
			UnitOfWorkManager.Current.OnCompleted(RemoveRealCache);
		}
		else
		{
			await RemoveRealCache();
		}
	}

	protected virtual void HandleException(Exception ex)
	{
		AsyncHelper.RunSync(() => HandleExceptionAsync(ex));
	}

	protected virtual async Task HandleExceptionAsync(Exception ex)
	{
		Logger.LogException(ex, LogLevel.Warning);

		using (var scope = ServiceScopeFactory.CreateScope())
		{
			await scope.ServiceProvider
				.GetRequiredService<IExceptionNotifier>()
				.NotifyAsync(new ExceptionNotificationContext(ex, LogLevel.Warning));
		}
	}

	protected virtual KeyValuePair<TCacheKey, TCacheItem>[] ToCacheItems<TCacheItem, TCacheKey>(byte[][] itemBytes, TCacheKey[] itemKeys) where TCacheItem: class
	{
		if (itemBytes.Length != itemKeys.Length)
		{
			throw new AbpException("count of the item bytes should be same with the count of the given keys");
		}

		var result = new List<KeyValuePair<TCacheKey, TCacheItem>>();

		for (int i = 0; i < itemKeys.Length; i++)
		{
			result.Add(
				new KeyValuePair<TCacheKey, TCacheItem>(
					itemKeys[i],
					ToCacheItem<TCacheItem>(itemBytes[i])
				)
			);
		}

		return result.ToArray();
	}

	[CanBeNull]
	protected virtual TCacheItem ToCacheItem<TCacheItem>([CanBeNull] byte[] bytes) where TCacheItem : class
	{
		if (bytes == null)
		{
			return null;
		}

		return Serializer.Deserialize<TCacheItem>(bytes);
	}


	protected virtual KeyValuePair<string, byte[]>[] ToRawCacheItems<TCacheItem, TCacheKey>(KeyValuePair<TCacheKey, TCacheItem>[] items, string cacheName)
	{
		return items
			.Select(i => new KeyValuePair<string, byte[]>(
					NormalizeKey(i.Key, cacheName),
					Serializer.Serialize(i.Value)
				)
			).ToArray();
	}

	private static KeyValuePair<TCacheKey, TCacheItem>[] ToCacheItemsWithDefaultValues<TCacheItem, TCacheKey>(TCacheKey[] keys)
	{
		return keys
			.Select(key => new KeyValuePair<TCacheKey, TCacheItem>(key, default))
			.ToArray();
	}

	protected virtual bool ShouldConsiderUow(bool considerUow)
	{
		return considerUow && UnitOfWorkManager.Current != null;
	}

	protected virtual string GetUnitOfWorkCacheKey()
	{
		return UowCacheName + CacheName;
	}

	protected virtual Dictionary<TCacheKey, UnitOfWorkCacheItem<TCacheItem>> GetUnitOfWorkCache<TCacheItem, TCacheKey>() where TCacheItem : class
	{
		if (UnitOfWorkManager.Current == null)
		{
			throw new AbpException($"There is no active UOW.");
		}

		return UnitOfWorkManager.Current.GetOrAddItem(GetUnitOfWorkCacheKey(),
			key => new Dictionary<TCacheKey, UnitOfWorkCacheItem<TCacheItem>>());
	}
}

[Dependency(ReplaceServices = true)]
public class WantDistributedCacheKeyNormalizer : IDistributedCacheKeyNormalizer, ITransientDependency
{
	protected AbpDistributedCacheOptions DistributedCacheOptions { get; }

	public SuncereDistributedCacheKeyNormalizer(
		IOptions<AbpDistributedCacheOptions> distributedCacheOptions)
	{
		DistributedCacheOptions = distributedCacheOptions.Value;
	}

	public virtual string NormalizeKey(DistributedCacheKeyNormalizeArgs args)
	{
		// 缓存格式: a:appname,c:cachename,k:key
		var normalizedKey = $"a:{DistributedCacheOptions.KeyPrefix},c:{args.CacheName},k:{args.Key}";
		return normalizedKey;
	}
}

[DependsOn(typeof(AbpCachingModule))]
public class WantAbpCacheModule : AbpModule
{
	public override void ConfigureServices(ServiceConfigurationContext context)
	{
		//注入缓存类
		context.Services.AddSingleton(typeof(ISuncereDistributedCache), typeof(SuncereDistributedCache));
	}
}


参考文章:
ABP 官方文档 - 缓存



ABP 系列总结:
目录:ABP 系列总结
上一篇:ABP - 缓存模块(1)

标签:缓存,模块,cache,value,hideErrors,ABP,item,key,null
From: https://www.cnblogs.com/wewant/p/17135175.html

相关文章

  • 缓存的常见问题以及SpringCache的解决方案
    总体来说,缓存在使用的过程中主要面临以下几个问题:缓存击穿(某个热点数据的key失效了)缓存中无数据,但是数据库中有数据,由于是热点key,如果同一时间大量请求进来会导致数据库压力大增缓存雪崩与缓存击穿类似,只不过缓存雪崩是多个热点key同时失效缓存穿透查询不存在的数据,当同时......
  • 基于DSP的设备振动信号的采集和处理模块研发总结
    前记 在能源领域,由于很多地方都是无人值守,设备故障检测是一个必须面对的问题。笔者通过最近几个行业案例了解到,由于很多设备发生故障时候会产生特定频谱的声音,所以该行业对振动监测的需求特别强烈,由于涉及到个性化的方案定制和处理,市面上此类的解决方案特别少。笔者希望把最近的......
  • 24W机壳式AC-DC降压开关电源模块AP21-24W24N产品简介
    输入电压:100~250V输出电压:24V输出电流:1000mA输出功率:24W产品尺寸:85*58*33mm安装方式:螺丝固定功能特点:高精度工业电源产品简介:AP21-24W24N是一款小体积机壳式开关电源,交流直流两用,输入电压85~264Vac/100~370Vdc,超低纹波、超低功耗、高效率、安全隔离、高可靠性等优点;符合IEC60950......
  • 创建型模式-单例模式(使用模块实现)
    singletion模块classTest():passa=Test() 调用模块fromsingleton.testimportaif__name__=="__main__":foriteminrange(10):b=aprint(id(b))......
  • ABP VNext事件总线-本地事件
    1、本地事件分为发布事件和订阅事件,其中,发布事件和订阅事件都必须要注册到ID中,使用接口ITransientDependency来注册,方便让事件总线发现并注册他们。2、发布事件需要使用ID获取ILocalEventBus服务,在定义一个发布方法之后,使用该服务的PublishAsync()方法来发布事件//定义一......
  • 高并发下的缓存穿透
    高并发下的缓存穿透什么是缓存穿透大量并发去访问一个数据库不存在的数据,由于缓存中没有该数据导致大量并发查询数据库,这个现象要缓存穿透。缓存穿透可以造成数据库瞬间压力过大,连接数等资源用完,最终数据库拒绝连接不可用。如何解决缓存穿透对请求增加校验机制比如:课程......
  • 高并发下的缓存击穿
    高并发下的缓存击穿什么是缓存击穿缓存击穿是指大量并发访问同一个热点数据,当热点数据失效后同时去请求数据库,瞬间耗尽数据库资源,导致数据库无法使用。比如某手机新品发布,当缓存失效时有大量并发到来导致同时去访问数据库。如何解决缓存击穿使用同步锁控制查询数据库的......
  • 高并发下的缓存雪崩
    高并发下的缓存雪崩什么是缓存雪崩缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。造成缓存雪崩问题的原因是是大量key拥有了相同的过期时间,比如对课程信息设置缓存过期时间为10分钟,在大量请求同时查询大量的......
  • 织梦功能模块模板路径对应表
     首页模板\templets\default\index.html文章频道首页\templets\default\index_article.htm文章列表页\templets\default\list_article.htm文章内容页\templets\default\article_article.htm图集频道首页\templets\default\index_image.htm图集列表页\templets\def......
  • 【TypeScript】Element 组件导入在 TypeScript 5 报错:模块 ““element-plus““ 没有
    报错现象解决方法typescript5.0版本升级,使用了compilerOptions.moduleResolution:"bundler"的模块编译选项。moduleResolution:模块解析策略,是指编译器在查找导入模块内容时所遵循的流程因此目前要解决报错,我们只需要修改tsconfig.json下的为node就行。/*Bundle......