博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何使用缓存提高程序性能
阅读量:5978 次
发布时间:2019-06-20

本文共 7948 字,大约阅读时间需要 26 分钟。

1 写在前面

此文主要参考了园子里以下两篇文章:

黄聪,

顾磊, 

2 前面两篇博文写的很好,很全面,为何还需要本文?

大家可以点进去看下前面的文章,黄聪写的是企业库Cache基本用法,顾磊的文章比较深入,而且自定义了CacheHelper类,实用性更强,我也抄袭了这个类(^_^ )。

我写此文的目的主要是记录下如果在项目中引入操作Cache、缓存哪些内容及最后的单元测试等

主要是在缓存哪些数据的问题上,可能和顾磊的文章有些不同。 

3 项目中引入Cache

首先从微软网站下载并安装Enterprise Library 5.0 我这里Cache主要用在DataAccess这个项目中,是一个类库项目,所以Config的东西先不用配置,直接添加Microsoft.Practices.EnterpriseLibrary.Caching.dll的引用,

然后添加CacheHelper类,代码: 

ExpandedBlockStart.gif
View Code 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using System.Reflection;
namespace DataAccess
{
    
public 
static 
class CacheHelper
    {
        
private 
static ICacheManager cache = CacheFactory.GetCacheManager();
        
///
 
<summary>
        
///
 Add Cache
        
///
 
</summary>
        
///
 
<param name="key"></param>
        
///
 
<param name="value"></param>
        
///
 
<param name="isRefresh">
if true, should reload data every 5 mins; default value = false
</param>
        
public 
static 
void Add(
string key, 
object value, 
bool isRefresh)
        {
            
if (isRefresh)
                cache.Add(key, value, CacheItemPriority.Normal, 
new ATSCacheItemRefreshAction(), 
new AbsoluteTime(TimeSpan.FromMinutes(
5)));
            
else
                cache.Add(key, value);
        }
        
//
 Summary:
        
//
     Adds new CacheItem to cache. If another item already exists with the same
        
//
     key, that item is removed before the new item is added. If any failure occurs
        
//
     during this process, the cache will not contain the item being added. Items
        
//
     added with this method will be not expire, and will have a Normal Microsoft.Practices.EnterpriseLibrary.Caching.CacheItemPriority
        
//
     priority.
        
//
        
//
 Parameters:
        
//
   key:
        
//
     Identifier for this CacheItem
        
//
        
//
   value:
        
//
     Value to be stored in cache. May be null.
        
//
        
//
 Exceptions:
        
//
   System.ArgumentNullException:
        
//
     Provided key is null
        
//
        
//
   System.ArgumentException:
        
//
     Provided key is an empty string
        
//
        
//
 Remarks:
        
//
     The CacheManager can be configured to use different storage mechanisms in
        
//
     which to store the CacheItems.  Each of these storage mechanisms can throw
        
//
     exceptions particular to their own implementations.
        
public 
static 
void Add(
string key, 
object value)
        {
            Add(key, value, 
false);
        }
        
public 
static 
object Get(
string key)
        {
            
return cache.GetData(key);
        }
        
public 
static 
void Remove(
string key)
        {
            cache.Remove(key);
        }
    }
    [Serializable]
    
public 
class ATSCacheItemRefreshAction : ICacheItemRefreshAction
    {
        
#region ICacheItemRefreshAction Members
        
public 
void Refresh(
string removedKey, 
object expiredValue, CacheItemRemovedReason removalReason)
        {
            
//
when expired, reload it.
            
if (removalReason == CacheItemRemovedReason.Expired)
            {
                ICacheManager c = CacheFactory.GetCacheManager();
                c.Add(removedKey, expiredValue);
            }
        }
        
#endregion
    }

4 缓存数据

在顾磊的文章中,他主要缓存一些Class,如ClassInfoServiceStudentService等,代码如下: 

ExpandedBlockStart.gif
View Code 
///
 
<summary>
        
///
 通用对象反射(包含缓存)
        
///
 
</summary>
        
///
 
<param name="className">
要反射的类名
</param>
        
///
 
<returns></returns>
        
public 
static T CreateObject(
string className)
        {
            
var typeName = assemblyString + 
"
.
" + className;
            
//
判断对象是否被缓存,如果已经缓存则直接从缓存中读取,反之则直接反射并缓存
            
var obj = (T)CacheHelper.GetCache(typeName);
            
if (obj == 
null)
            {
                obj = (T)Assembly.Load(assemblyString).CreateInstance(typeName, 
true);
                CacheHelper.Add(typeName, obj, 
true);
            }
            
return obj;
        }
public 
static IStudentService CreateStudent()
        {
            
string typeName = assemblyString + 
"
.StudentService
";
            
if (CacheHelper.GetCache(typeName) != 
null)
            {
                
return (IStudentService)CacheHelper.GetCache(typeName);
            }
            
else
            {
                IStudentService service = (IStudentService)Assembly.Load(assemblyString).CreateInstance(typeName, 
true);
                CacheHelper.Add(typeName, service, 
true);
                
return service;
            }

而像StudentService这种Class,如果New StudentService()这样一个实例的话,所占的CPU和内存都是很小的,我觉得更有必要的是缓存数据,从数据库中查询回来的数据。

我们看下顾磊代码中如何操作数据的:

class StudentManage 

ExpandedBlockStart.gif
View Code 
private 
static 
readonly IStudentService studentService = DataAccess<IStudentService>.CreateObject(
"
StudentService
");
public Student SelectById(
int id)
        {
            
return studentService.SelectById(id);

class StudentService 

ExpandedBlockStart.gif
View Code 
        
///
 
<summary>
        
///
 根据学生ID查询学生对象
        
///
 
</summary>
        
///
 
<param name="id">
学生ID
</param>
        
///
 
<returns></returns>
        
public Student SelectById(
int id)
        {
            Student student = 
null;
            Database db = DBHelper.CreateDataBase();
            StringBuilder sb = 
new StringBuilder();
            sb.Append(
"
select * from Student 
");
            sb.Append(
"
 where ID=@ID
");
            DbCommand cmd = db.GetSqlStringCommand(sb.ToString());
            db.AddInParameter(cmd, 
"
@ID
", DbType.Int32, id);
 
            
using (IDataReader reader = db.ExecuteReader(cmd))
            {
                
if (reader.Read())
                {
                    student = 
new Student()
                    {
                        Id = reader.GetInt32(
0),
                        ClassId = reader.GetInt32(
1),
                        Sid = reader.GetString(
2),
                        Password = reader.GetString(
3),
                        Name = reader.GetString(
4),
                        Sex = reader.GetInt32(
5),
                        Birthday = reader.GetDateTime(
6),
                        IsAdmin = reader.GetInt32(
7)
                    };
                }
            }
 
            
return student;

大家从上面的代码可以看出,缓存中存放了StudentService这个类,但是在SelectByIdint id)这个函数中,并没有缓存任何东西,还是每次从数据库中查询数据,这样设计缓存,对程序性能的提升是十分有限的。

5 我程序中如何缓存数据

我还是用上面顾磊的代码吧,那个好理解。然后我将每次查询到的数据缓存起来,如果下次查询,先从缓存中取数据,有则自动返回数据;没有,则从数据库中查询,然后添加到缓存中,缓存有自动的数据过期机制,过期的数据会自动删除。 

ExpandedBlockStart.gif
View Code 
public Student SelectByIdWithCache(
int id)
        {
            Student student = (Student)CacheHelper.GetCache(id.ToString());
            
if (student == 
null)
            {
                student = SelectById(id);
                CacheHelper.Add(id.ToString(), student);
            }
            
return student;

这里可能上面的代码不是十分恰当,但是为了让大家更清楚我的意图,及上面的代码十分简洁、易懂。 

主要是我项目程序中有这样的特情况,查询参数是一个TableParameters,里面有很多字段: 

ExpandedBlockStart.gif
View Code 
public 
class TableParameters : IParameters<tblTable>
    {
        
public Guid? tableGuid { 
get
set; }
        
public 
string tableName { 
get
set; }
        
public 
string tableDesc { 
get
set; }
        
public Guid? tableTypeGuid { 
get
set; }
        
public Guid? schemeGuid { 
get
set; }
        
public Guid index1TypeGuid { 
get
set; }
        
public Guid? latestTableVersionGuid { 
get
set; }
        
public Guid? tableFormatGuid { 
get
set; }
        
public Guid? index2TypeGuid { 
get
set; }

在第一次会通过一个条件,查询得到一个List,之后会直接传输一个Guid过来,而这个guid往往会包含在上面的结果中,所以第一件会将List缓存,详细代码: 

ExpandedBlockStart.gif
View Code 
public List<tblTable> GetQueryList(IParameters<tblTable> t)
        {
            TableParameters param = (TableParameters)t;
            List<tblTable> query = 
new List<tblTable>();
            
if (param.tableGuid != 
null)
            {
                tblTable result = (tblTable)CacheHelper.Get(GuidTable + param.tableGuid.Value.ToString());
                
if (result != 
null)
                {                  
                    query.Add(result);
                    
return query;
                }
            }
            
var _tableQuery = 
from c 
in db.tblTable.Expand(
"
TableType
").Expand(
"
TableFormat
").Expand(
"
Scheme
").Expand(
"
Index1Type
").Expand(
"
Index2Type
").Expand(
"
LatestTableVersionGUID
")
                                               
select c;
            
if (param.tableGuid != 
null)
            {
                _tableQuery = _tableQuery.Where(n => n.TableGUID == param.tableGuid.Value);
            }
            
if (!
string.IsNullOrEmpty(param.tableName))
            {
                _tableQuery = _tableQuery.Where(n => n.TableName.Contains(param.tableName));
            }
            
if (param.tableTypeGuid != 
null)
            {
                _tableQuery = _tableQuery.Where(n => n.TableType.TableTypeGUID == param.tableTypeGuid.Value);
            }
            
if (param.tableFormatGuid != 
null)
            {
                _tableQuery = _tableQuery.Where(n => n.TableFormat.TableFormatGUID == param.tableFormatGuid.Value);
            }
            
if (param.schemeGuid != 
null)
                _tableQuery = _tableQuery.Where(n => n.Scheme.SchemeGUID == param.schemeGuid.Value);
            
            query = _tableQuery.ToList<tblTable>();
            
foreach (
var tb 
in query)
            {
                CacheHelper.Add(GuidTable + tb.TableGUID.ToString(), tb);
            }
            
return query;

6 单元测试

这个单元测试不是测试顾磊代码的,是我项目中测试TableManager的,因为顾磊的代码更简明,所以上面我还是贴出了他的代码,至于单元测试,还是随便贴个我项目的,因为顾磊那个我没数据,没法写,呵呵~  

ExpandedBlockStart.gif
View Code 
        
///
 
<summary>
        
///
A test for GetQueryList
        
///
</summary>
        [TestMethod()]
        
public 
void GetQueryListTest()
        {
           
            TableParameters t = 
new TableParameters();
            t.schemeGuid = 
new Guid(
"
9C962C55-A598-40B8-A39B-11788161A9D8
");
           
            List<tblTable> actual;
            actual = ManagerFactory.TableManager.GetQueryList(t);
            Assert.AreEqual(
"
 Sedgwick Marsh- B & pre2000-NRA65
", actual[
0].TableName);
            
//
Assert.Inconclusive("Verify the correctness of this test method.");

7 总结

我认为缓存数据不仅仅要缓存Class类,更要缓存从数据库中查询过来的数据,这样才能最大限度的提示程序性能。

8 声明

以上纯为技术交流,对顾磊、黄聪等技术牛人十分敬佩,文中也引用了他们的文中和大量代码,再次感谢。 

转载于:https://www.cnblogs.com/4kapple/archive/2011/12/31/2308619.html

你可能感兴趣的文章
plsql乱码解决
查看>>
Linux 初始化 init 系统
查看>>
使用简易Python爬虫下载百度贴吧图片
查看>>
【转载】2013年全国各大著名的IT公司薪资待遇大揭密
查看>>
Java并发编程高级篇(六):在执行器中延时执行任务
查看>>
Hbase 超详细架构解析
查看>>
SSH隧道
查看>>
Android 屏幕旋转 处理 AsyncTask 和 ProgressDialog 的最佳方案
查看>>
Java中容器的迭代器的fail-fast机制
查看>>
BackTrack5 whois
查看>>
使用 Scalable Performance Monitor 监控 和分析 solr的运行状况
查看>>
比较好的网站及工具
查看>>
Slack监视中的sql查询
查看>>
PythonForDataAnalysis-study_2
查看>>
Undefined symbols for architecture armv7
查看>>
snapchat拒绝Fb收购说起
查看>>
Spring Transaction Manager
查看>>
dubbo负载均衡代码分析3(加权轮询策略)
查看>>
CentOS环境 升级Python2.6.6至2.7.6
查看>>
Cordova ajax http 请求失败的解决方法,xcode 7 更新plist支持http
查看>>