大家好,我是沙漠尽头的狼。

上文介绍了《C#使用CefSharp内嵌网页-并给出C#与JS的交互示例》,本文介绍CefSharp的缓存实现,先来说说添加缓存的好处:

  1. 提高页面加载加速:CefSharp缓存可以缓存已经加载过的页面和资源,当用户再次访问相同的页面时,可以直接从缓存中加载,而不需要重新下载和解析页面和资源,从而加快页面加载速度。
  2. 减少网络流量:使用缓存可以减少网络流量,因为已经下载过的资源可以直接从缓存中读取,而不需要重新下载。
  3. 提高用户体验:由于缓存可以提高页面加载速度,因此可以提高用户的体验,用户可以更快地访问页面和资源,从而更加愉快地使用应用程序。
  4. 减少服务器负载:使用缓存可以减少服务器的负载,因为已经下载过的资源可以直接从缓存中读取,而不需要重新生成和发送。
  5. 离线访问:可以使应用程序支持离线访问,因为它可以缓存已经下载过的页面和资源,当用户没有网络连接时,可以直接从缓存中加载页面和资源。

总之,使用缓存可以提高应用程序的性能和用户体验,减少网络流量和服务器负载,并支持离线访问,是一个非常有用的特性。

本文示例:Github

断网情况下,演示加载已经缓存的百度百度翻译Dotnet9首页Dotnet9关于4个页面:

接下来讲解缓存的实现方式。

1. 默认缓存实现

CefSharp的默认缓存实现方式是基于Chromium的缓存机制。Chromium使用了两种类型的缓存:内存缓存和磁盘缓存。

1.1. 内存缓存

内存缓存是一个基于LRU(最近最少使用)算法的缓存,它缓存了最近访问的页面和资源。内存缓存的大小是有限的,当缓存达到最大大小时,最近最少使用的页面和资源将被删除。

内存缓存无法通过CefSharp.WPF的API进行设置。具体来说,Chromium会在内存中维护一个LRU(Least Recently Used)缓存,用于存储最近访问的网页数据。当缓存空间不足时,Chromium会根据LRU算法自动清除最近最少使用的缓存数据,以腾出空间存储新的数据。

在CefSharp.WPF中,我们可以通过调用Cef.GetGlobalRequestContext().ClearCacheAsync()方法来清除内存缓存中的数据。该方法会清除所有缓存数据,包括内存缓存和磁盘缓存。如果只需要清除内存缓存,可以调用Cef.GetGlobalRequestContext().ClearCache(CefCacheType.MemoryCache)方法。

需要注意的是,由于内存缓存是由Chromium自身维护的,因此我们无法直接控制其大小。如果需要控制缓存大小,可以通过设置磁盘缓存的大小来间接控制内存缓存的大小。

1.2. 磁盘缓存

磁盘缓存是一个基于文件系统的缓存,它缓存了已经下载的页面和资源。磁盘缓存的大小也是有限的,当缓存达到最大大小时,最早的页面和资源将被删除。

CefSharp.WPF的磁盘缓存是通过设置CefSettings中的CachePath属性来实现的。具体来说,我们可以通过以下代码设置磁盘缓存的路径:

  1. public partial class App : Application
  2. {
  3. protected override void OnStartup(StartupEventArgs e)
  4. {
  5. base.OnStartup(e);
  6. // CachePath需要为绝对路径
  7. var settings = new CefSettings
  8. {
  9. CachePath = $"{AppDomain.CurrentDomain.BaseDirectory}DefaultCaches"
  10. };
  11. Cef.Initialize(settings);
  12. }
  13. }

缓存目录结构如下:

其中,CachePath属性指定了磁盘缓存的路径(绝对路径)。如果不设置该属性,Chromium会将缓存数据存储在默认路径下(通常是用户目录下的AppData\Local\CefSharp目录)。

需要注意的是,磁盘缓存的大小是由Chromium自身控制的,我们可以通过设置CacheController的SetCacheLimit方法来控制缓存数据存储在磁盘上的最大空间。该方法接受一个long类型的参数,表示缓存数据的最大大小(单位为字节)。例如,以下代码将磁盘缓存的最大大小设置为100MB:

  1. var cacheController = Cef.GetGlobalRequestContext().CacheController;
  2. cacheController.SetCacheLimit(100 * 1024 * 1024); // 100MB

需要注意的是,Chromium会根据LRU算法自动清除最近最少使用的缓存数据,以腾出空间存储新的数据。因此,即使设置了缓存大小,也不能保证所有数据都会被缓存。如果需要清除磁盘缓存中的数据,可以调用Cef.GetGlobalRequestContext().ClearCacheAsync()方法。

默认的缓存站长研究不多,上面的代码和描述通过ChatGPT搜索得来,我们来看自定义缓存的实现,默认缓存只是个引子。

2. 自定义缓存

这是本文介绍的重点,相对于默认缓存,自定义缓存有以下好处:

  1. 更加灵活:可以根据应用程序的需求来灵活地配置缓存策略和缓存大小,从而更好地满足应用程序的需求。
  2. 更好的性能:可以根据应用程序的需求和特定的场景进行配置,以获得更好的性能。默认的缓存可能不适合某些特定的场景或者不适合您的应用程序的需求,而自定义缓存则可以根据您的需求进行调整,以获得更好的性能。
  3. 更好的安全性:可以更好地保护用户的隐私和安全,因为可以控制缓存中存储的内容和缓存的生命周期。
  4. 更加可控:可以更好地控制缓存的行为,例如可以控制缓存的清除时间和清除策略,从而更好地管理缓存。
  5. 更好的兼容性:可以更好地适应不同的浏览器和设备,默认的缓存可能不能提供足够的兼容性,而自定义缓存则可以根据您的需求进行调整,以提供更好的兼容性。
  6. 更加高效:可以更好地利用系统资源,例如可以使用更快的存储设备来存储缓存,从而提高缓存的读写速度。

总结:自定义缓存可以提供更好的性能、响应性、安全性和兼容性,从而提高应用程序的质量和用户体验,人话就是更好的操控

2.1. 代码实现

注释前面加的默认缓存代码。

2.1.1. 注册资源请求拦截处理程序

首先在使用ChromiumWebBrowser控件的后台代码里,注册请求拦截处理程序,CefBrowser是控件名,CefRequestHandlerc是处理程序:

  1. public TestCefCacheView()
  2. {
  3. InitializeComponent();
  4. var handler = new CefRequestHandlerc();
  5. CefBrowser.RequestHandler = handler;
  6. }

2.1.2. 请求拦截处理程序

CefSharp里的IRequestHandler是一个接口,用于处理浏览器发出的请求。它定义了一些方法,可以在请求被发送到服务器之前或之后对请求进行处理。

IRequestHandler的实现类可以用于以下几个方面:

  1. 拦截请求:可以通过实现OnBeforeBrowse方法来拦截请求,从而控制浏览器的行为。例如,可以在请求被发送到服务器之前检查请求的URL,如果不符合要求,则可以取消请求或者重定向到其他页面。

  2. 修改请求:可以通过实现OnBeforeResourceLoad方法来修改请求,例如可以添加一些自定义的HTTP头信息,或者修改请求的URL。

  3. 处理响应:可以通过实现OnResourceResponse方法来处理服务器返回的响应,例如可以检查响应的状态码和内容,从而决定是否继续加载页面。

  4. 缓存控制:可以通过实现OnQuotaRequest方法来控制缓存的大小和清除策略,从而优化缓存的使用。

总之,IRequestHandler的实现类可以用于控制浏览器的行为,优化网络请求和缓存的使用,从而提高应用程序的性能和用户体验。

我们不直接实现接口IRequestHandler,而是继承它的一个默认实现类RequestHandler,这可以简化我们的开发,毕竟实现接口要列出一系列接口方法。

我们重载方法GetResourceRequestHandler, 在这个方法里返回CefResourceRequestHandler实例,页面中资源请求时会调用此方法:

  1. using CefSharp;
  2. using CefSharp.Handler;
  3. namespace WpfWithCefSharpCacheDemo.Caches;
  4. internal class CefRequestHandlerc : RequestHandler
  5. {
  6. protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame,
  7. IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
  8. {
  9. // 一个请求用一个CefResourceRequestHandler
  10. return new CefResourceRequestHandler();
  11. }
  12. }

2.1.3. 资源请求拦截程序

在CefSharp中,IResourceRequestHandler接口是用于处理资源请求的,它可以拦截浏览器发出的资源请求,例如图片、CSS、JavaScript等,从而实现对资源请求的控制和优化。

具体来说,IResourceRequestHandler接口定义了一些方法,例如OnBeforeResourceLoadOnResourceResponse等方法,这些方法可以用于拦截请求、修改请求、处理响应等方面。例如:

  1. OnBeforeResourceLoad:在浏览器请求资源之前被调用,可以用于修改请求,例如添加一些自定义的HTTP头信息,或者修改请求的URL。

  2. OnResourceResponse:在浏览器接收到服务器返回的响应之后被调用,可以用于处理响应,例如检查响应的状态码和内容,从而决定是否继续加载页面。

  3. OnResourceLoadComplete:在资源加载完成后被调用,可以用于处理资源加载完成后的操作,例如保存资源到本地缓存。

通过实现IResourceRequestHandler接口,可以对资源请求进行拦截和优化,从而提高应用程序的性能和用户体验。

这里我们也不直接实现IResourceRequestHandler接口,我们定义CefResourceRequestHandler类,继承该接口的默认实现类ResourceRequestHandler

在下面的CefResourceRequestHandler类中:

  1. GetResourceHandler方法:处理资源是否需要缓存,返回null不缓存,返回CefResourceHandler表示需要缓存,在这个类中做跨域处理。
  2. GetResourceResponseFilter方法:注册资源缓存的操作类,即资源下载的实现。
  3. OnBeforeResourceLoad方法:在这个方法里,我们可以实现给页面传递header参数。
  1. using System.Collections.Specialized;
  2. using CefSharp;
  3. using CefSharp.Handler;
  4. namespace WpfWithCefSharpCacheDemo.Caches;
  5. internal class CefResourceRequestHandler : ResourceRequestHandler
  6. {
  7. private string _localCacheFilePath;
  8. private bool IsLocalCacheFileExist => System.IO.File.Exists(_localCacheFilePath);
  9. protected override IResourceHandler? GetResourceHandler(IWebBrowser chromiumWebBrowser, IBrowser browser,
  10. IFrame frame, IRequest request)
  11. {
  12. try
  13. {
  14. _localCacheFilePath = CacheFileHelper.CalculateResourceFileName(request.Url, request.ResourceType);
  15. if (string.IsNullOrWhiteSpace(_localCacheFilePath))
  16. {
  17. return null;
  18. }
  19. }
  20. catch
  21. {
  22. return null;
  23. }
  24. if (!IsLocalCacheFileExist)
  25. {
  26. return null;
  27. }
  28. return new CefResourceHandler(_localCacheFilePath);
  29. }
  30. protected override IResponseFilter? GetResourceResponseFilter(IWebBrowser chromiumWebBrowser, IBrowser browser,
  31. IFrame frame,
  32. IRequest request, IResponse response)
  33. {
  34. return IsLocalCacheFileExist ? null : new CefResponseFilter { LocalCacheFilePath = _localCacheFilePath };
  35. }
  36. protected override CefReturnValue OnBeforeResourceLoad(IWebBrowser chromiumWebBrowser, IBrowser browser,
  37. IFrame frame, IRequest request,
  38. IRequestCallback callback)
  39. {
  40. var headers = new NameValueCollection(request.Headers);
  41. headers["Authorization"] = "Bearer xxxxxx.xxxxx.xxx";
  42. request.Headers = headers;
  43. return CefReturnValue.Continue;
  44. }
  45. }

2.1.4. CefResourceHandler

在CefSharp中,IResourceHandler接口是用于处理资源的,它可以拦截浏览器发出的资源请求,并返回自定义的资源内容,从而实现对资源的控制和优化。

具体来说,IResourceHandler接口定义了一些方法,例如ProcessRequestGetResponseHeadersReadResponse等方法,这些方法可以用于处理资源请求、获取响应头信息、读取响应内容等方面。例如:

  1. ProcessRequest:在浏览器请求资源时被调用,可以用于处理资源请求,例如从本地缓存中读取资源内容,或者从网络中下载资源内容。

  2. GetResponseHeaders:在浏览器请求资源时被调用,可以用于获取响应头信息,例如设置响应的MIME类型、缓存策略等。

  3. ReadResponse:在浏览器请求资源时被调用,可以用于读取响应内容,例如从本地缓存中读取资源内容,或者从网络中下载资源内容。

通过实现IResourceHandler接口,可以对资源进行自定义处理,例如从本地缓存中读取资源内容,从而提高应用程序的性能和用户体验。

这里我们也不直接实现IResourceHandler接口,我们定义CefResourceHandler类,继承该接口的默认实现类ResourceHandler

CefResourceHandler的构造函数里只处理跨域问题,其他需求可通过上面接口的方法查找资料处理即可:

  1. using CefSharp;
  2. using System.IO;
  3. namespace WpfWithCefSharpCacheDemo.Caches;
  4. internal class CefResourceHandler : ResourceHandler
  5. {
  6. public CefResourceHandler(string filePath, string mimeType = null, bool autoDisposeStream = false,
  7. string charset = null) : base()
  8. {
  9. if (string.IsNullOrWhiteSpace(mimeType))
  10. {
  11. var fileExtension = Path.GetExtension(filePath);
  12. mimeType = Cef.GetMimeType(fileExtension);
  13. mimeType = mimeType ?? DefaultMimeType;
  14. }
  15. var stream = File.OpenRead(filePath);
  16. StatusCode = 200;
  17. StatusText = "OK";
  18. MimeType = mimeType;
  19. Stream = stream;
  20. AutoDisposeStream = autoDisposeStream;
  21. Charset = charset;
  22. Headers.Add("Access-Control-Allow-Origin", "*");
  23. }
  24. }

2.1.5. CefResponseFilter

在CefSharp中,IResponseFilter接口是用于过滤响应内容的,它可以拦截浏览器接收到的响应内容,并对其进行修改或者过滤,从而实现对响应内容的控制和优化。

具体来说,IResponseFilter接口定义了一些方法,例如InitFilterFilterGetSize等方法,这些方法可以用于初始化过滤器、过滤响应内容、获取过滤后的响应内容大小等方面。例如:

  1. InitFilter:在浏览器接收到响应内容时被调用,可以用于初始化过滤器,例如设置过滤器的状态、获取响应头信息等。

  2. Filter:在浏览器接收到响应内容时被调用,可以用于过滤响应内容,例如修改响应内容、删除响应内容等。

  3. GetSize:在浏览器接收到响应内容时被调用,可以用于获取过滤后的响应内容大小,例如用于计算响应内容的压缩比例等。

站长使用的CefSharp.Wpf89.0.170.0版本中的IResponseFilter接口没有GetSize方法。在该版本中,IResponseFilter接口只定义了两个方法:InitFilterFilter

如果在该版本中您需要获取过滤后的响应内容大小,可以考虑在Filter方法中自行计算。例如,在Filter方法中,您可以将过滤后的响应内容写入一个缓冲区,并记录缓冲区的大小,最后返回过滤后的响应内容和缓冲区的大小。

  1. public class MyResponseFilter : IResponseFilter
  2. {
  3. private MemoryStream outputStream = new MemoryStream();
  4. public void Dispose()
  5. {
  6. outputStream.Dispose();
  7. }
  8. public bool InitFilter()
  9. {
  10. return true;
  11. }
  12. public FilterStatus Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten)
  13. {
  14. dataInRead = 0;
  15. dataOutWritten = 0;
  16. byte[] buffer = new byte[4096];
  17. int bytesRead = 0;
  18. do
  19. {
  20. bytesRead = dataIn.Read(buffer, 0, buffer.Length);
  21. if (bytesRead > 0)
  22. {
  23. outputStream.Write(buffer, 0, bytesRead);
  24. }
  25. } while (bytesRead > 0);
  26. byte[] outputBytes = outputStream.ToArray();
  27. dataOut.Write(outputBytes, 0, outputBytes.Length);
  28. dataInRead = outputBytes.Length;
  29. dataOutWritten = outputBytes.Length;
  30. return FilterStatus.Done;
  31. }
  32. public int GetResponseFilterBufferSize()
  33. {
  34. return 0;
  35. }
  36. public int GetResponseFilterDelay()
  37. {
  38. return 0;
  39. }
  40. }

在上述示例代码中,我们在Filter方法中将过滤后的响应内容写入了一个MemoryStream对象中,并记录了缓冲区的大小。最后,我们在Filter方法的返回值中返回了过滤后的响应内容和缓冲区的大小。

总结,通过实现IResponseFilter接口,可以对响应内容进行自定义处理,例如对响应内容进行压缩、加密等操作,从而提高应用程序的性能和安全性。

本文示例这里定义类CefResponseFilter直接实现接口处理文件缓存实际操作类,即资源下载实现:

  1. using CefSharp;
  2. using System.IO;
  3. namespace WpfWithCefSharpCacheDemo.Caches;
  4. internal class CefResponseFilter : IResponseFilter
  5. {
  6. public string LocalCacheFilePath { get; set; }
  7. private const int BUFFER_LENGTH = 1024;
  8. private bool isFailCacheFile;
  9. public FilterStatus Filter(Stream? dataIn, out long dataInRead, Stream? dataOut, out long dataOutWritten)
  10. {
  11. dataInRead = 0;
  12. dataOutWritten = 0;
  13. if (dataIn == null)
  14. {
  15. return FilterStatus.NeedMoreData;
  16. }
  17. var length = dataIn.Length;
  18. var data = new byte[BUFFER_LENGTH];
  19. var count = dataIn.Read(data, 0, BUFFER_LENGTH);
  20. dataInRead = count;
  21. dataOutWritten = count;
  22. dataOut?.Write(data, 0, count);
  23. try
  24. {
  25. CacheFile(data, count);
  26. }
  27. catch
  28. {
  29. // ignored
  30. }
  31. return length == dataIn.Position ? FilterStatus.Done : FilterStatus.NeedMoreData;
  32. }
  33. public bool InitFilter()
  34. {
  35. try
  36. {
  37. var dirPath = Path.GetDirectoryName(LocalCacheFilePath);
  38. if (!string.IsNullOrWhiteSpace(dirPath) && !Directory.Exists(dirPath))
  39. {
  40. Directory.CreateDirectory(dirPath);
  41. }
  42. }
  43. catch
  44. {
  45. // ignored
  46. }
  47. return true;
  48. }
  49. public void Dispose()
  50. {
  51. }
  52. private void CacheFile(byte[] data, int count)
  53. {
  54. if (isFailCacheFile)
  55. {
  56. return;
  57. }
  58. try
  59. {
  60. if (!File.Exists(LocalCacheFilePath))
  61. {
  62. using var fs = File.Create(LocalCacheFilePath);
  63. fs.Write(data, 0, count);
  64. }
  65. else
  66. {
  67. using var fs = File.Open(LocalCacheFilePath, FileMode.Append);
  68. fs.Write(data,0,count);
  69. }
  70. }
  71. catch
  72. {
  73. isFailCacheFile = true;
  74. File.Delete(LocalCacheFilePath);
  75. }
  76. }
  77. }

2.1.6. CacheFileHelper

缓存文件帮助类,用于管理页面的ajax接口缓存白名单、缓存文件路径规范等:

  1. using CefSharp;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. namespace WpfWithCefSharpCacheDemo.Caches;
  6. internal static class CacheFileHelper
  7. {
  8. private const string DEV_TOOLS_SCHEME = "devtools";
  9. private const string DEFAULT_INDEX_FILE = "index.html";
  10. private static HashSet<string> needInterceptedAjaxInterfaces = new();
  11. private static string CachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "caches");
  12. public static void AddInterceptedAjaxInterfaces(string url)
  13. {
  14. if (needInterceptedAjaxInterfaces.Contains(url))
  15. {
  16. return;
  17. }
  18. needInterceptedAjaxInterfaces.Add(url);
  19. }
  20. private static bool IsNeedInterceptedAjaxInterface(string url, ResourceType resourceType)
  21. {
  22. var uri = new Uri(url);
  23. if (DEV_TOOLS_SCHEME == url)
  24. {
  25. return false;
  26. }
  27. if (ResourceType.Xhr == resourceType && !needInterceptedAjaxInterfaces.Contains(url))
  28. {
  29. return false;
  30. }
  31. return true;
  32. }
  33. public static string? CalculateResourceFileName(string url, ResourceType resourceType)
  34. {
  35. if (!IsNeedInterceptedAjaxInterface(url, resourceType))
  36. {
  37. return default;
  38. }
  39. var uri = new Uri(url);
  40. var urlPath = uri.LocalPath;
  41. if (urlPath.StartsWith("/"))
  42. {
  43. urlPath = urlPath.Substring(1);
  44. }
  45. var subFilePath = urlPath;
  46. if (ResourceType.MainFrame == resourceType || string.IsNullOrWhiteSpace(urlPath))
  47. {
  48. subFilePath = Path.Combine(urlPath, DEFAULT_INDEX_FILE);
  49. }
  50. var hostCachePath = Path.Combine(CachePath, uri.Host);
  51. var fullFilePath = Path.Combine(hostCachePath, subFilePath);
  52. return fullFilePath;
  53. }
  54. }

自定义缓存的子目录以资源的域名(Host)为目录名称创建:

打开缓存的dotnet9.com目录,通过查看目录结构和程序发布目录基本一致,这更适合人看了,是不?

2.2. 可能存在的问题

第一点,站长目前遇到的问题,后面4点由Token AI提供解释。

2.2.1. 对缓存的资源URL带QueryString的方式支持不好

建议用Route(路由的方式:https://dotnet9.com/albums/wpf)代替QueryString(查询参数的试工:https://dotnet9.com/albums?slug=wpf)的方式,站长有空再研究下QueryString的缓存方式。

如果确实资源带QueryString,那对于这种资源就放开缓存,直接通过网络请求吧。

2.2.2. 缓存一致性问题

如果自定义缓存不正确地处理了缓存一致性,可能会导致浏览器显示过期的内容或者不一致的内容。例如,如果缓存了一个网页,但是该网页在服务器上已经被更新了,如果自定义缓存没有正确地处理缓存一致性,可能会导致浏览器显示过期的网页内容。

2.2.3. 缓存空间问题

如果自定义缓存没有正确地管理缓存空间,可能会导致浏览器占用过多的内存或者磁盘空间。例如,如果自定义缓存缓存了大量的数据,但是没有及时清理过期的数据或者限制缓存的大小,可能会导致浏览器占用过多的内存或者磁盘空间。

2.2.4. 缓存性能问题

如果自定义缓存没有正确地处理缓存性能,可能会导致浏览器的性能下降。例如,如果自定义缓存没有正确地处理缓存的读取和写入,可能会导致浏览器的响应速度变慢。

2.2.5. 缓存安全问题

如果自定义缓存没有正确地处理缓存安全,可能会导致浏览器的安全性受到威胁。例如,如果自定义缓存缓存了敏感数据,但是没有正确地处理缓存的加密和解密,可能会导致敏感数据泄露。

因此,在自定义缓存时,需要注意处理缓存一致性、缓存空间、缓存性能和缓存安全等问题,以确保浏览器的正常运行和安全性。

参考:

CefSharp自定义缓存实现的更多相关文章

  1. 【.net 深呼吸】自定义缓存配置(非Web项目)

    在前一篇烂文中,老周简单讲述了非Web应用的缓存技术的基本用法.其实嘛,使用系统默认方案已经满足我们的需求了,不过,如果你真想自己来配置缓存,也是可以的. 缓存的自定义配置可以有两种方案,一种是用代码 ...

  2. 借鉴dubbo实现自定义缓存

    自定义缓存一般基于ConcurrentMap实现,实现缓存需要注意的点是缓存容器对象 本身依赖于 static final去存储对象,样例: ConcurrentMap<String, Gene ...

  3. MyBatis 一、二级缓存和自定义缓存

    1.一级缓存 ​ MyBatis 默认开启了一级缓存,一级缓存是在SqlSession 层面进行缓存的.即,同一个SqlSession ,多次调用同一个Mapper和同一个方法的同一个参数,只会进行一 ...

  4. redis学习总结-redis作为MyBatis的自定义缓存

    1.RedisCache.java package com.houtai.cache; import java.util.concurrent.locks.ReadWriteLock; import ...

  5. (转)MyBatis 一、二级缓存和自定义缓存

    1.一级缓存 MyBatis 默认开启了一级缓存,一级缓存是在SqlSession 层面进行缓存的.即,同一个SqlSession ,多次调用同一个Mapper和同一个方法的同一个参数, 只会进行一次 ...

  6. 自定义缓存管理器 或者 Spring -- cache

    Spring Cache 缓存是实际工作中非常常用的一种提高性能的方法, 我们会在许多场景下来使用缓存. 本文通过一个简单的例子进行展开,通过对比我们原来的自定义缓存和 spring 的基于注释的 c ...

  7. .Net Core 跨平台开发实战-服务器缓存:本地缓存、分布式缓存、自定义缓存

    .Net Core 跨平台开发实战-服务器缓存:本地缓存.分布式缓存.自定义缓存 1.概述 系统性能优化的第一步就是使用缓存!什么是缓存?缓存是一种效果,就是把数据结果存在某个介质中,下次直接重用.根 ...

  8. mybatis 自定义缓存 cache

    缓存不管哪个框架都是显得特别的重要,今天自己测试实现了mybatis自定义缓存,从而理解mybatis缓存的工作原理. 首先缓存类要实现Cache接口:具体实现如下package com.ibatis ...

  9. Spring-Redis缓存业务优化(通配符删除、两种自定义缓存时长)

    application.yml配置 spring:    cache:     type: REDIS     redis:       time-to-live: PT300S # 默认缓存秒数   ...

  10. 【.NET Core项目实战-统一认证平台】第五章 网关篇-自定义缓存Redis

    [.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章我们介绍了2种网关配置信息更新的方法和扩展Mysql存储,本篇我们将介绍如何使用Redis来实现网关的所有缓存功能,用到的文档及源码 ...

随机推荐

  1. 【QT5】学习整理包含引用资料

    视频学习资料 [[6天学会QT] 视频教程及QT5.11.1安装包安装方法][含代码]](https://www.bilibili.com/video/BV1hg4y1B7Vu?from=search ...

  2. 切片slice

    1.切片 切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用类型的机制 切片的使用和数组类似,如遍历切片,访问切片的元素和求切片长度len(slice)都一样. 切片的长度是可以变化的, ...

  3. 火狐浏览器调试eval源码

    火狐浏览器调试eval源码 firefox浏览器在网页调试上,有一个没法和chrome一比高下的功能,就是eval脚本的调试,有时前端架构使用了基于eval的方式,有时候可能是自己一个多行函数,每每遇 ...

  4. TensorFlow安装填坑之路(Windows环境)

    最近跟着简单粗暴 TensorFlow 2中的教学活动ML Study Jam 2020学习TensorFlow,记录下在Windows环境中安装TensorFlow时遇到的那些坑. TensorFl ...

  5. k8sdeploy配置文件示例

    apiVersion: extensions/v1beta1 kind: Deployment metadata: name: [k8s服务名] namespace: default labels: ...

  6. windows下使用route添加路由

    1,首先在"运行"窗口输入cmd(按WIN+R打开运行窗口),然后回车进入命令行. 2,在命令行下输入route命令,会有对应的提示信息. ROUTE [-f] [-p] [-4| ...

  7. ASP.NET Core Web API Swagger 按标签Tags分组排序显示

    需求 swagger页面按标签Tags分组显示. 没有打标签Tags的接口,默认归到"未分组". 分组内按接口路径排序 说明 为什么没有使用GroupName对接口进行分组? 暂时 ...

  8. Typora怎么插入行内公式?内联公式设置

    文件 偏好设置 把内联公式那个勾上就可以了.然后就能写latex了,像这样,$\alpha\$ \(\alpha\) 输入一个\$后再按esc,会自动补全为$$

  9. keyclaok~keycloak存到cookie中的值和session_state

    keycloak存到cookie中的值 AUTH_SESSION_ID KEYCLOAK_IDENTITY KEYCLOAK_SESSION AUTH_SESSION_ID 用户的当前session_ ...

  10. [GIT]指定分支下创建分支

    1 解决方案 Eg: master分支下创建 $ git checkout master //切换到master分支下 $ git branch branch_tmp_A //在本地仓库创建临时分支b ...