XAF使用数据库访问层缓存的提升性能

1、XAF使用Cache缓存原始帖

https://supportcenter.devexpress.com/ticket/details/k18356/how-to-use-xpo-data-layer-caching-in-xaf

2、XAF使用会话层缓存

会话层缓存 默认情况下,XPO在会话级别缓存记录。因为大多数XAF根视图都有自己的会话,所以每个根视图都有自己的缓存。当视图关闭或其对象空间被重新加载时,该缓存被重置。此外,大多数数据库系统都提供了一种高级的缓存机制,可以更快地执行相同SQL查询的后续调用。在大多数情况下,这种功能足以实现良好的性能。如果数据库服务器连接延迟很长,并且有大量重复查询,那么在数据存储级别实现缓存可能会有所帮助。

数据层缓存要启用数据存储级缓存,请将应用程序连接到缓存的数据存储。在这种情况下,应用程序缓存数据库查询及其结果。如果应用程序第二次执行相同的查询,缓存的数据将从内存中加载。DataCacheNode和DataCacheNodeLocal对象执行缓存。将这些对象连接到一个共享的DataCacheRoot对象。DataCacheRoot同步不同缓存节点中所做的更改。因此,一次只能将一个根目录连接到数据库。您需要通过它传递所有的数据修改。若要重置或清除数据存储表上的任何缓存信息(如表更新信息和缓存的查询结果),请使用NotifyDirtyTables或reset()方法(请参见有关仅为特定类型重置数据存储缓存的问题中的代码示例)。有关内置XPO缓存策略及其差异的更多信息,请参见会话管理和缓存。

3、示例代码方法:

3.1. 在解决方案名称中项目,使用以下代码添加CachedDataStoreProvider.cs文件. 

public class CachedDataStoreProvider : ConnectionStringDataStoreProvider, IXpoDataStoreProvider {
static CachedDataStoreProvider() {
Factory = () => default;
CreateStore = () => default;
CustomCreateUpdatingStore = () => default;
}

private static readonly Lazy<CachedDataStoreProvider> Lazy = new(()
=> Factory() ?? new CachedDataStoreProvider(StaticConnectionString));

public static string StaticConnectionString { get; set; }

public static Func<CachedDataStoreProvider> Factory { get; set; }

private static IDisposable[] _rootDisposableObjects;
private static DataCacheRoot _root;

public static CachedDataStoreProvider Instance => Lazy.Value;

public CachedDataStoreProvider(string connectionString) : base(connectionString) {
}

public static readonly Func<(bool allowUpdateSchema, IDisposable[] rootDisposables, IDataStore dataStore)> CustomCreateUpdatingStore;

public static readonly Func<(IDisposable[] rootDisposables, IDataStore dataStore)> CreateStore;

public new IDataStore CreateWorkingStore(out IDisposable[] disposableObjects)
=> ((IXpoDataStoreProvider) this).CreateWorkingStore(out disposableObjects);

IDataStore IXpoDataStoreProvider.CreateUpdatingStore(bool allowUpdateSchema,
out IDisposable[] disposableObjects) {
var store = CustomCreateUpdatingStore();
if (store.IsDefaultValue()) {
return base.CreateUpdatingStore(allowUpdateSchema, out disposableObjects);
}

disposableObjects = store.rootDisposables;
return store.dataStore;
}

IDataStore IXpoDataStoreProvider.CreateWorkingStore(out IDisposable[] disposableObjects) {
if (_root == null) {
var tuple = CreateStore();
IDataStore baseDataStore;
if (tuple.IsDefaultValue()) {
baseDataStore = base.CreateWorkingStore(out _rootDisposableObjects);
}
else {
baseDataStore = tuple.dataStore;
_rootDisposableObjects = tuple.rootDisposables;
}

_root = new DataCacheRoot(baseDataStore);
}

disposableObjects = Array.Empty<IDisposable>();
return new DataCacheNode(_root);
}

public static void ResetDataCacheRoot() {
_root = null;
if (_rootDisposableObjects != null) {
foreach (var disposableObject in _rootDisposableObjects) disposableObject.Dispose();
_rootDisposableObjects = null;
}
}
}

3.2. 在启动中ConfigureServices 增加下面代码:

1.netcore 6.0之上

public void ConfigureServices(IServiceCollection services)

{

// ... services.AddSingleton<IXpoDataStoreProvider>((serviceProvider) => { string connectionString = null;

if(Configuration.GetConnectionString("ConnectionString") != null)

{ connectionString = Configuration.GetConnectionString("ConnectionString"); }

#if EASYTEST

if(Configuration.GetConnectionString("EasyTestConnectionString") != null)

{ connectionString = Configuration.GetConnectionString("EasyTestConnectionString"); }

#endif

ArgumentNullException.ThrowIfNull(connectionString);

return new CachedDataStoreProvider(connectionString, connection: null, enablePoolingInConnectionString: true);

});

// ...

builder.ObjectSpaceProviders
.AddSecuredXpo((serviceProvider, options) => {
//options.ConnectionString = GetConnectionString(serviceProvider);
//var useMemoryStore = false;
//options.EnablePoolingInConnectionString = !useMemoryStore;
//options.ThreadSafe = true;
//options.UseSharedDataStoreProvider = true;
options.ThreadSafe = true;
var cachedDataStoreProvider = serviceProvider.GetRequiredService<IXpoDataStoreProvider>();
ArgumentNullException.ThrowIfNull(cachedDataStoreProvider);
options.UseCustomDataStoreProvider(cachedDataStoreProvider);
})
.AddNonPersistent();

2. .netcore 5下等:

protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) {
        args.ObjectSpaceProvider = new CachedObjectSpaceProvider(args.ConnectionString, args.Connection);
    }

4.使用SqlDependency

需要注意的是:这个缓存只能在web中使用,或者在如果你有多个web服务器连接到一台DB时,也是不行的。

如有两台WEB,A,B 当A做了修改数据行为后,B服务器并不知道这个数据库中的数据已经修改,所以B仍去缓存中读取数据。

同样的,Win程序的缓存是在客户端电脑上的,所以也像多WEB一样有问题。

我搜索了官方的解决方案:

当使用了SqlServer时,可以用Service Broker 查询通知服务,进行通知客户端。这是一个方向。由于我考虑兼容性,比如用oracle或是别的库时也想有这个样的功能,所以没有用这个。

当然,如果你的web应用只是在一台服务器上部署就不用考虑这个问题了。

//_root = new DataCacheRoot(baseDataStore);

//sql conn add Persist Security Info=true
//ALTER DATABASE DatabaseName SET NEW_BROKER WITH ROLLBACK IMMEDIATE;
//ALTER DATABASE Databasename SET ENABLE_BROKER;
_root = MSSql2005SqlDependencyCacheRoot.CreateSqlDependencyCacheRoot((MSSqlConnectionProvider)baseDataStore, cacheConfig, out _rootDisposableObjects);

5.在efcore中如何使用sqldependency进行缓存

https://github.com/dyatchenko/ServiceBrokerListener

监听变更,进行缓存管理

6.在mysql中使用Binlog监控日志变更

https://github.com/VahidN/EFCoreSecondLevelCacheInterceptor

 

posted @ 2023-10-29 09:58  精耕细琢  阅读(16)  评论(0编辑  收藏  举报