用IBatisNet作为持久层工具,有一个很好的好处就是很方便地使用它本身的缓存模型,可以控制在数据修改后缓存过期,但它的限制也是相当明显的,数据缓存和数据的更新操作必须在同一个应用程序域当中,当我在一台机器上缓存数据,而在另一台机器上修改数据(或者直接修改数据表)时就无法通知缓存过期了,在POST提供解决这一问题的一个思路和方法。
用IBatisNet作为持久层工具,有一个很好的好处就是很方便地使用它本身的缓存模型,可以控制在数据修改后缓存过期,但它的限制也是相当明显的,数据缓存和数据的更新操作必须在同一个应用程序域当中,当我在一台机器上缓存数据,而在另一台机器上修改数据(或者直接修改数据表)时就无法通知缓存过期了。这一个很棘手的问题,到底要不要使用缓存呢?在Asp.Net 2.0 当中有提供一个运行Sql Server的数据库更新通知缓存过期策略,(实现Cache SqlDependency,请参阅SQL Cache Dependency With SQL Server 2000),我可以将数据读取到UI层,然后再UI层再将数据缓存到HttpContext.Cache当中,再设置一个SqlDependency依赖,将它与指定的表做更新依赖。显然这样的做法是可行的,但如果就这样使用在当前的项目中,变得得不偿失。由于当前的DAL分为接口和实现,再结合Castle的IOC容器,实现组件的松耦合,可以随时改变接口的实现部分,尽管说做到改变数据库还是一个理论上的意愿,但是在UI层就将系统与Sql Server数据绑死(SqlDependency只支持Sql Server),显然与系统整体结构互相矛盾。最好的办法是在数据访问层直接就实现数据的缓存功能,这样数据是否实现缓存,如何缓存就对数据访问者来说就是透明的。还有一个需要考虑的问题是,对于数据访问层来说,它应该是独立于程序的架构(B/S,C/S),也就是对于一个程序来说,不管是C/S还是B/S结构的,应该可以使用同一个的数据访问层,这边就还需要考虑到HttpContext.Cache的使用问题了。不过这倒不是很难解决的问题,HttpContext.Cache的时候判断一下对象是否为空就行了。
缓存KEY的生成也是一个大问题,Ibatisnet的缓存模型,可是做到同一个查询语句根据参数的值的来缓存数据,比如:这个查询的条件为1,而下次的查询条件仍为1时就会先去缓存读取数据,而如果为2时就会直接去数据库查询数据。在Ibatisnet中有一个专门的CacheKey类来做为缓存的key,而HttpContext.Cache只接收string类型的缓存KEY,在这边就必须根据Ibatisnet动态生成的Sql语句和参数值进行拼接做为缓存的key。为了保证数据一定时间不用后及时过期,不浪费太多内存,还应该缓每个缓存项添加相对时间过期策略。
下面贴出对Ibatisnet的查询接口的适配方法。做个笔记。


1
public class MapperAdapter
2
{
3
public SqlMapper GetMapper()
4
{
5
return IBatisNet.DataMapper.Mapper.Instance();
6
}
7
private HttpContext BsContext = HttpContext.Current;
8
9
private SqlMapSession m_sqlSession;
10
public MapperAdapter()
11
{
12
m_sqlSession = new SqlMapSession(GetMapper().DataSource);
13
}
14
15
/**//// <summary>
16
/// Queries for list.
17
/// </summary>
18
/// <param name="statementName">语句名称.</param>
19
/// <param name="parameterObject">参数.</param>
20
/// <param name="p_strTableName">缓存过期依赖表</param>
21
/// <returns></returns>
22
public GenericObjectListWrapper<T> QueryForList<T>(string statementName, object parameterObject, string p_strTableName)
23
where T : DataObjectBase
24
{
25
return QueryForList<T>(statementName, parameterObject, -1, -1, p_strTableName);
26
}
27
28
/**//// <summary>
29
/// Queries for list.
30
/// </summary>
31
/// <param name="statementName">Name of the statement.</param>
32
/// <param name="parameterObject">The parameter object.</param>
33
/// <param name="skipResult">The skip result.</param>
34
/// <param name="maxResult">The max result.</param>
35
/// <param name="p_strTableName">过期依赖表名</param>
36
/// <returns></returns>
37
public GenericObjectListWrapper<T> QueryForList<T>(string statementName, object parameterObject,
38
int skipResult, int maxResult, string p_strTableName)
39
where T : DataObjectBase
40
{
41
string cacheKey = GetCacheKey("QueryForList", statementName, parameterObject);
42
GenericObjectListWrapper<T> m_list = Cache_Get(cacheKey) as GenericObjectListWrapper<T>;
43
if (m_list == null)
44
{
45
m_list = new GenericObjectListWrapper<T>(GetMapper().QueryForList(statementName, parameterObject, skipResult, maxResult) as ObjectList);
46
Cache_Add(cacheKey, m_list, p_strTableName);
47
}
48
return m_list;
49
}
50
51
public IDictionary QueryForDictionary(string statementName, object parameterObject, string keyProperty, string p_strTableName)
52
{
53
return QueryForMap(statementName, parameterObject, keyProperty, p_strTableName);
54
}
55
/**//// <summary>
56
/// Queries for dictionary.
57
/// </summary>
58
/// <param name="statementName">Name of the statement.</param>
59
/// <param name="parameterObject">The parameter object.</param>
60
/// <param name="keyProperty">The key property.</param>
61
/// <param name="valueProperty">.</param>
62
/// <param name="p_strTableName">过期依赖表名.</param>
63
/// <returns></returns>
64
public IDictionary QueryForDictionary(string statementName, object parameterObject, string keyProperty, string valueProperty,
65
string p_strTableName)
66
{
67
return QueryForMap(statementName, parameterObject, keyProperty, valueProperty, p_strTableName);
68
}
69
/**//// <summary>
70
/// Queries for map.
71
/// </summary>
72
/// <param name="statementName">Name of the statement.</param>
73
/// <param name="parameterObject">The parameter object.</param>
74
/// <param name="keyProperty">The key property.</param>
75
/// <param name="p_strTableName">过期依赖表名.</param>
76
/// <returns></returns>
77
public IDictionary QueryForMap(string statementName, object parameterObject, string keyProperty, string p_strTableName)
78
{
79
return QueryForMap(statementName, parameterObject, keyProperty, null);
80
}
81
82
/**//// <summary>
83
/// Queries for map.
84
/// </summary>
85
/// <param name="statementName">Name of the statement.</param>
86
/// <param name="parameterObject">The parameter object.</param>
87
/// <param name="keyProperty">The key property.</param>
88
/// <param name="valueProperty">The value property.</param>
89
/// <param name="p_strTableName">过期依赖表名.</param>
90
/// <returns></returns>
91
public IDictionary QueryForMap(string statementName, object parameterObject, string keyProperty,
92
string valueProperty, string p_strTableName)
93
{
94
string cacheKey = GetCacheKey("QueryForMap", statementName, parameterObject);
95
IDictionary dictionary = Cache_Get(cacheKey) as IDictionary;
96
if (dictionary == null)
97
{
98
dictionary = GetMapper().QueryForMap(statementName, parameterObject, keyProperty, valueProperty);
99
Cache_Add(cacheKey, dictionary, p_strTableName);
100
}
101
return dictionary;
102
}
103
104
public T QueryForObject<T>(string statementName, object parameterObject, string p_strTableName)
105
where T : DataObjectBase
106
{
107
string cacheKey = GetCacheKey("QueryForObject", statementName, parameterObject);
108
T dataObject = Cache_Get(cacheKey) as T;
109
if (dataObject == null)
110
{
111
dataObject = GetMapper().QueryForObject(statementName, parameterObject) as T;
112
Cache_Add(cacheKey, dataObject, p_strTableName);
113
}
114
return dataObject;
115
}
116
117
/**//// <summary>
118
/// Queries for object.
119
/// </summary>
120
/// <param name="statementName">Name of the statement.</param>
121
/// <param name="parameterObject">The parameter object.</param>
122
/// <param name="resultObject">The result object.</param>
123
/// <param name="p_strTableName">过期依赖表名.</param>
124
/// <returns></returns>
125
public T QueryForObject<T>(string statementName, object parameterObject, T resultObject, string p_strTableName)
126
where T : DataObjectBase
127
{
128
string cacheKey = GetCacheKey("QueryForObject", statementName, parameterObject);
129
resultObject = Cache_Get(cacheKey) as T;
130
if (resultObject == null)
131
{
132
resultObject = GetMapper().QueryForObject(statementName, parameterObject, resultObject) as T;
133
Cache_Add(cacheKey, resultObject, p_strTableName);
134
}
135
return resultObject;
136
}
137
Cache Help#region Cache Help
138
/**//// <summary>
139
/// Gets the cache key.生成缓存KEY
140
/// </summary>
141
/// <param name="p_strExecuteMethodName">Name of the P_STR execute method.</param>
142
/// <param name="statementName">Name of the statement.</param>
143
/// <param name="parameterObject">The parameter object.</param>
144
/// <returns></returns>
145
private string GetCacheKey(string p_strExecuteMethodName, string statementName, object parameterObject)
146
{
147
IMappedStatement mappedStatement = GetMapper().GetMappedStatement(statementName);
148
RequestScope requestScope = mappedStatement.Statement.Sql.GetRequestScope(parameterObject, m_sqlSession);
149
150
//
151
// 通过这个方法生成一个DbCommand,并且给所有的SQL参数指定值。如果没有调用此方法,requestScope.IDbCommand属性为空
152
//
153
mappedStatement.PreparedCommand.Create(requestScope, m_sqlSession, mappedStatement.Statement, parameterObject);
154
PreparedStatement preparedStatement = requestScope.PreparedStatement;
155
156
StringBuilder cacheKey = new StringBuilder(p_strExecuteMethodName + ":" + mappedStatement.Statement.Id + ";");
157
cacheKey.Append(" SQL:" + preparedStatement.PreparedSql);
158
cacheKey.Append(" Parameters:");
159
foreach (object obj in requestScope.IDbCommand.Parameters)
160
{
161
DbParameter parameter = (DbParameter)obj;
162
cacheKey.Append(string.Format("{0}={1};", parameter.ParameterName, parameter.Value));
163
}
164
return cacheKey.ToString();
165
}
166
167
protected virtual object Cache_Get(string p_strKey)
168
{
169
if (BsContext != null)
170
{
171
return BsContext.Cache.Get(p_strKey);
172
}
173
return null;
174
}
175
176
protected virtual void Cache_Add(string p_strKey, object p_value, string p_strTableName)
177
{
178
if (BsContext != null && p_value != null)
179
{
180
SqlCacheDependency m_sqlDependency = new SqlCacheDependency("CommonSqlDependency", p_strTableName);
181
BsContext.Cache.Insert(p_strKey, p_value, m_sqlDependency, DateTime.MaxValue, TimeSpan.Parse("00:30:00"));
182
}
183
}
184
#endregion
185
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述