‘壹’ vb.net如何实现缓存处理
首先~~需要确认的是,每次读取花时间的问题~是在连接上还是在创建实例上。
如果是在创建实例上,需要做【单例模式】,建议所有数据创建在Mole中,并做全局变量。
Cache是一种B/S,的MVC方式。
缓存方式有很多~~~
一种是物理方式(做物理RAM内存开避空间)
一种是文件方式(做文件)
如文件方式,较常出现的如MVC的缓存,就是大概原理就是,把不经常用到(变化)的数据信息放到文件中,采用读取文件的方式(比访问数据快),存在指定或CurrentDir中。
如果想方便~需要追加一系列状态标识~当访问时,触发变更,然后在读取数据前,确认这个状态是否变动,如果变动说明数据库有变动,需要再次访问数据库。如果没有变动,则读取文件。
这种就叫缓存技术。
当然,我说的这种是比较简单的,还是需要设计思想。
‘贰’ asp.net 三层架构在业务层中如何使用Cache
利用memcahed缓存服务器,缓存数据持久层查询来的数据,供表示层调用
‘叁’ 谁做过业务逻辑层的缓存处理
你要缓存服务器,写个类,弄个静态变量就可以了
‘肆’ 如何使用redis做mysql的缓存
大方向两种方案:
1.脚本同步:
自己写脚本将数据库数据写入到redis/memcached。
这就涉及到实时数据变更的问题(mysql row binlog的实时分析),binlog增量订阅Alibaba 的canal ,以及缓存层数据 丢失/失效 后的数据同步恢复问题。
2.业务层实现:
先读取nosql缓存层,没有数据再读取mysql层,并写入数据到nosql。
nosql层做好多节点分布式(一致性hash),以及节点失效后替代方案(多层hash寻找相邻替代节点),和数据震荡恢复了。
作者:liu kelin
链接:https://www.hu.com/question/27738066/answer/84920552
来源:知乎
着作权归作者所有,转载请联系作者获得授权。
‘伍’ 如何用redis/memcache做Mysql缓存层
1、首先明确是不是一定要上缓存,当前架构的瓶颈在哪里,若瓶颈真是数据库操作上,再继续往下看。
2、明确memcached和redis的区别,到底要使用哪个。前者终究是个缓存,不可能永久保存数据(LRU机制),支持分布式,后者除了缓存的同时也支持把数据持久化到磁盘等,redis要自己去实现分布式缓存(貌似最新版本的已集成),自己去实现一致性hash。因为不知道应用场景,不好说一定要用memcache还是redis,说不定用mongodb会更好,比如在存储日志方面。
3、缓存量大但又不常变化的数据,比如评论。
4、思路是对的,清晰明了,读DB前,先读缓存,如果有直接返回,如果没有再读DB,然后写入缓存层并返回。
5、考虑是否需要主从,读写分离,考虑是否分布式部署,考虑是否后续水平伸缩。
6、想要一劳永逸,后续维护和扩展方便,那就将现有的代码架构优化,按你说的替换数据库组件需要改动大量代码,说明当前架构存在问题。可以利用现有的一些框架,比如SpringMVC,将应用层和业务层和数据库层解耦。再上缓存之前把这些做好。
7、把读取缓存等操作做成服务组件,对业务层提供服务,业务层对应用层提供服务。
8、保留原始数据库组件,优化成服务组件,方便后续业务层灵活调用缓存或者是数据库。
9、不建议一次性全量上缓存,最开始不动核心业务,可以将边缘业务先换成缓存组件,一步步换至核心业务。
10、刷新内存,以memcached为例,新增,修改和删除操作,一般采用lazy load的策略,即新增时只写入数据库,并不会马上更新Memcached,而是等到再次读取时才会加载到Memcached中,修改和删除操作也是更新 数据库,然后将Memcached中的数据标记为失效,等待下次读取时再加载。
大方向两种方案:
1、脚本同步:
自己写脚本将数据库数据写入到redis/memcached。
这就涉及到实时数据变更的问题(mysql row binlog的实时分析),binlog增量订阅Alibaba 的canal ,以及缓存层数据 丢失/失效 后的数据同步恢复问题。
2、业务层实现:
先读取nosql缓存层,没有数据再读取mysql层,并写入数据到nosql。
nosql层做好多节点分布式(一致性hash),以及节点失效后替代方案(多层hash寻找相邻替代节点),和数据震荡恢复了。
‘陆’ 如何使用缓存
缓存是分层次的,下面是计算机缓存山:
cpu缓存策略:
寄存器中计算数据,而数据存储在内存中,由于cpu和内存之间的性能逐渐增大,系统设计者在cpu和内存之间插入了3层的高速缓存。高速缓存有三个层级,就是整个计算机缓存系统的一个小缩影。
‘柒’ 如何在service层加入redis缓存
//放入缓存注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public@interfaceCacheable{//放入
Stringkey();//缓存key
StringfieldKey();//field值
intexpireTime()default3600;
}
//从缓存中销毁注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public@interfaceCacheEvict{//销毁
Stringkey();
String[]fieldKey();
intexpireTime()default3600;
}
Aspect类
//环绕切入
@Around(value="@annotation(com.xx.cache.annotation.Cacheable)")
publicObjectcache(ProceedingJoinPointpjp){
Objectresult=null;
Methodmethod=getMethod(pjp);
Cacheablecacheable=method.getAnnotation(Cacheable.class);
StringfieldKey=cacheable.fieldKey();
if(cacheable.fieldKey().indexOf("#")==0){//动态变量存入方式
fieldKey=parseKey(cacheable.fieldKey(),method,pjp.getArgs());
}
if(useCache){//判断是否开启缓存开启缓存从缓存获取result
//获取方法的返回类型,让缓存可以返回正确的类型
ClassreturnType=((MethodSignature)pjp.getSignature()).getReturnType();
//使用redis的hash进行存取,易于管理
//result=JedisUtils.hget(cacheable.key(),fieldKey,method.getReturnType());
result=JedisUtils.hget(cacheable.key(),fieldKey,returnType);
if(result==null){
try{
result=pjp.proceed();
//Assert.notNull(fieldKey);
JedisUtils.hset(cacheable.key(),fieldKey,result);
logger.debug("The"+cacheable.key()+"addtoredis,thefieldKeyis"+fieldKey);
}catch(Throwablee){
e.printStackTrace();
}
}
returnresult;
}
try{
returnpjp.proceed();
}catch(Throwablethrowable){
throwable.printStackTrace();
returnnull;
}
}
//环绕切入
@Around(value="@annotation(com.xx.cache.annotation.CacheEvict)")
publicObjectevict(ProceedingJoinPointpjp){
//和cache类似,使用Jedis.hdel()删除缓存即可
if(useCache){//判断是否开启缓存
Methodmethod=getMethod(pjp);
CacheEvictcacheEvict=method.getAnnotation(CacheEvict.class);
String[]fieldKeys=cacheEvict.fieldKey();
intdeleteSuccessFlag=0;
for(StringfieldKey:fieldKeys){
if(fieldKey.indexOf("#")==0){//动态变量存入方式
Stringt=fieldKey;
fieldKey=parseKey(fieldKey,method,pjp.getArgs());
if(fieldKey==null){
logger.error("cacheevictfieldkey{}connotbenull,thatmaybecausedataconnotsync",t);
t=null;
}
}
deleteSuccessFlag+=JedisUtils.hdel(cacheEvict.key(),fieldKey==null?"":fieldKey);
logger.debug("Thereferencefieldkey:"+fieldKey+"for"+cacheEvict.key()+"hasbeendeletefromredis");
}
logger.debug("Delete"+deleteSuccessFlag+""+cacheEvict.key()+"fromredis");
}
try{
returnpjp.proceed();
}catch(Throwablee){
e.printStackTrace();
returnnull;
}
}
/**
*获取缓存的key
*key定义在注解上,支持SPEL表达式
*
*@paramkey
*@parammethod
*@paramargs
*@return
*/
privateStringparseKey(Stringkey,Methodmethod,Object[]args){
//获取被拦截方法参数名列表(使用Spring支持类库)
=();
String[]paraNameArr=u.getParameterNames(method);
//使用SPEL进行key的解析
ExpressionParserparser=newSpelExpressionParser();
//SPEL上下文
=newStandardEvaluationContext();
//把方法参数放入SPEL上下文中
for(inti=0;i<paraNameArr.length;i++){
context.setVariable(paraNameArr[i],args[i]);
}
returnparser.parseExpression(key).getValue(context,String.class);
}
使用,在service调用前使用:
@Cacheable(key="biz_member",fieldKey="#id")publicMemberget(Stringid){returnsuper.get(id);}@CacheEvict(key="member",fieldKey={"#member.id","#member.account"})publicSerializablesave(Membermember){return.insert(member);}@CacheEvict(key="member",fieldKey={"#member.id","#member.account"})publicvoiddelete(Membermember){.delete(member);}
‘捌’ 怎么实现redis的数据库的缓存
大致为两种措施:
一、脚本同步:
1、自己写脚本将数据库数据写入到redis/memcached。
2、这就涉及到实时数据变更的问题(mysql row binlog的实时分析),binlog增量订阅Alibaba 的canal ,以及缓存层数据 丢失/失效 后的数据同步恢复问题。
二、业务层实现:
1、先读取nosql缓存层,没有数据再读取mysql层,并写入数据到nosql。
2、nosql层做好多节点分布式(一致性hash),以及节点失效后替代方案(多层hash寻找相邻替代节点),和数据震荡恢复了。
‘玖’ asp.net缓存要注意些什么
asp.net性能的技巧
【IT168 技术文档】根据经验的总结,让我们来看看十个能帮助你提升你的应用程序性能的经验,我将按将它们提升效率的多少从大到小小依次说明。
一、返回多个数据集
检查你的访问数据库的代码,看是否存在着要返回多次的请求。每次往返降低了你的应用程序的每秒能够响应请求的次数。通过在单个数据库请求中返回多个结果集,可以减少与数据库通信的时间,使你的系统具有扩展性,也可以减少数据库服务器响应请求的工作量。
如果你是用动态的SQL语句来返回多个数据集,那我建议你用存储过程来替代动态的SQL语句。是否把业务逻辑写到存储过程中,这个有点争议。但是我认为,把业务逻辑写到存储过程里面可以限制返回结果集的大小,减小网络数据的流量,在逻辑层也不用在过滤数据,这是一个好事情。
用SqlCommand对象的ExecuteReader方法返回一个强类型的业务对象,再调用NextResult方法来移动数据集指针来定位数据集。示例一演示了一个返回多个ArrayList强类型对象的例子。只从数据库中返回你需要的数据可以大大的减小你的服务器所耗用的内存。
二、对数据进行分页
ASP.NET的DataGrid有一个非常有用的功能:分页。如果DataGrid允许分页,在某一时刻它只下载某一页的数据,另外,它有一个数据分页的浏览导航栏,它让你可以选择浏览某一页,而且每次只下载一页的数据。
但是它有一个小小的缺点,就是你必须把所有的数据都绑定到DataGrid中。也就是说,你的数据层必须返回所有的数据,然后DataGrid再根据当前页过滤出当前页所需要的数据显示出来。如果有一个一万条记录的结果集要用DataGrid进行分页,假设DataGrid每页只显示25条数据,那就意味着每次请求都有9975条数据都是要丢弃的。每次请求都要返回这么大的数据集,对应用程序的性能影响是非常大的。
一个好的解决方案是写一个分页的存储过程,例子2是一个用于对Northwind数据库orders表的分页存储过程。你只需要传当前页码,每页显示的条数两个参数进来,存储过程会返回相应的结果。
在服务器端,我专门写了一个分页的控件来处理数据的分页,在这里,我用了第一个方法,在一个存储过程里面返回了两个结果集:数据记录总数和要求的结果集。
返回的记录总数取决于要执行查询,例如,一个where条件可以限制返回的结果集的大小。因为在分页界面中必须要根据数据集记录的大小来计算总的页数,所以必须要返回结果集的记录数。例如,如果一共有1000000条记录,如果用where条件就可以过滤成只返回1000条记录,存储过程的分页逻辑应该知道返回那些需要显示的数据。
三、连接池
用TCP来连接你的应用程序与数据库是一件昂贵的事情(很费时的事情),微软的开发者可以通过用连接池来反复的使用数据库的连接。比起每次请求都用TCP来连一次数据库,连接池只有在不存在有效的连接时才新建一个TCP连接。当关闭一个连接的时候,它会被放到池中,它仍然会保持与数据库的连接,这样就可以减少与数据库的TCP连接次数。
当然,你要注意那些忘记关的连接,你应在每次用完连接后马上关闭它。我要强调的是:无论什么人说.NET Framework中的GC(垃圾收集器)总会在你用完连接对象后调用连接对象的Close或者Dispose方法显式的关闭你的连接。不要期望CLR会在你想象的时间内关掉连接,虽然CLR最终都要销毁对象和关闭边接,但是我们并不能确定它到底会在什么时候做这些事情。
要用连接池优化,有两条规则,第一,打开连接,处理数据,然后关闭连接。如果你必须在每次请求中多次打开或关闭连接,这好过一直打开一个边接,然后把它传到各个方法中。第二,用相同的连接字符串(或者用相同的用户标识,当你用集成认证的时候)。如果你没有用相同的连接字符串,如你用基于登录用户的连接字符串,这将不能利用连接池的优化功能。如果你用的是集成的论证,因为用户很多,所以你也不能充分利用连接池的优化功能。.NET CLR提供了一个数据性能计数器,它在我们需要跟踪程序性能特性的时候非常有用,当然也包括连接池的跟踪了。
无论你的应用程序什么时候要连在另一台机子的资源,如数据库,你都应该重点优化你连资源所花的时间,接收和发送数据的时间,以及往返回之间的次数。优化你的应用程序中的每一个处理点(process hop),它是提高你的应用的性能的出发点。
应用程序层包含与数据层连接,传送数据到相应的类的实例以及业务处理的逻辑。例如,在Community Server中,要组装一个Forums或者Threads集合,然后应用业务逻辑,如授权,更重要的,这里要完成缓存逻辑。
四、 ASP.NET缓存API
在写应用程序之前,你要做的第一件事是让应用程序最大化的利用ASP.NET的缓存功能。
如果你的组件是要在Asp.net应用程序中运行,你只要把System.Web.dll引用到你的项目中就可以了。然后用HttpRuntime.Cache属性就可访问Cache了(也可以通过Page.Cache或HttpContext.Cache访问)。
有以下几条缓存数据的规则。第一,数据可能会被频繁的被使用,这种数据可以缓存。第二,数据的访问频率非常高,或者一个数据的访问频率不高,但是它的生存周期很长,这样的数据最好也缓存起来。第三是一个常常被忽略的问题,有时候我们缓存了太多数据,通常在一台X86的机子上,如果你要缓存的数据超过800M的话,就会出现内存溢出的错误。所以说缓存是有限的。换名话说,你应该估计缓存集的大小,把缓存集的大小限制在10以内,否则它可能会出问题。在Asp.net中,如果缓存过大的话也会报内存溢出错误,特别是如果缓存大的DataSet对象的时候。
这里有几个你必须了解的重要的缓存机制。首先是缓存实现了“最近使用”原则( a least-recently-used algorithm),当缓存少的时候,它会自动的强制清除那些无用的缓存。其次 “条件依赖”强制清除原则(expiration dependencies),条件可以是时间,关键字和文件。以时间作为条件是最常用的。在asp.net2.0中增加一更强的条件,就是数据库条件。当数据库中的数据发生变化时,就会强制清除缓存。要更深入的了解数据库条件依赖请看Dino Esposito 在MSDN杂志2004年七月刊的Cutting Edge专栏文章。
五、 预请求缓存
在前面,我提到过即使我们只对某些地方作了一个小小的性能改进也可以获得大的性能提升,我非常喜欢用预请求缓存来提升程序的性能。
虽然Cache API设计成用来保存某段时间的数据,而预请求缓存只是保存某个时期的某个请求的内容。如果某个请求的访问频率高,而且这个请求只需要提取,应用,修改或者更新数据一次。那么就可以预缓存该请求。我们举个例子来说明。
在CS的论坛应用程序中,每一个页面的服务器控件都要求得到用于决定它的皮肤(skin)的自定义的数据,以决定用哪个样式表及其它的一些个性化的东西。这里面的某些数据可能要长时间的保存,有些时间则不然,如控件的skin数据,它只需要应用一次,而后就可以一直使用。
要实现预请求缓存,用Asp.net 的HttpContext类,HttpContext类的实例在每一个请求中创建,在请求期间的任何地方都可以通过HttpContext.Current属性访问。HttpContext类有一个Items集合属性,在请求期间所有的对象和数据都被添加到这个集合中缓存起来。和你用Cache缓存访问频率高数据一样,你可以用HttpContext.Items缓存那些每个请求都要用到的基础数据。它背后的逻辑很简单:我们向HttpContext.Items中添加一个数据,然后再从它里面读出数据。
‘拾’ asp.net 三层架构缓存问题
你好.
可以放在业务层进行缓存.
根据职责分配原则:
数据层只需要完成数据操作就可以,不适合缓存.
界面层只需要显示和交互,也不适合缓存.
当然你也可以增加一个层,专门做缓存功能.业务层去调用缓存层.
下面就是关键问题:当数据缓存了的话怎么在更新之后读取出来是最新的?
可以在业务层对数据做了:"修改","删除"操作之后,主动通知缓存层去更新缓存.
按这个思路去实现可能代码复杂些,但思路应该是可行的.
祝好!