发表于: 2016-04-20 21:47:15
1 2053
【操作步骤】
1.将Memcache这一技术具体应用于项目中,参考链接:http://blog.csdn.net/sup_heaven/article/details/32728477
1.1 修改以前项目中的ServiceImpl类,具体修改内容(以修改StudentServiceImpl类为例):以前的StudentServiceImpl类中我都是调用了dao层里的StudentMapper的方法来获取数据,现在我让它先利用MemcachedUtil.get来获取数据。但是只有“查”的方法需要改,“增删改”都不用改(我错了,“增删改”也需要改)。
【知识总结】
1.关于memcache:一个pool关联多个server(就是会根据权重将缓存放在这些servers上),一个client会通过poolName关联具体的pool。
2.将Memcache应用于具体项目中的思路是这样的(以获取Student的相关数据为例):
在没有使用Memcache以前,如果要从数据库获取数据,就需要直接调用StudentMapper的方法,通过StudentMapper.xml与数据库连接并获取数据,也就是说每次都要与数据库连接。
使用Memcache以后,如果要从数据库中获取数据,先从Memcache服务读取缓存好的数据,如果缓存中有相关数据,直接获取即可;如果缓存中没有所需数据,此时再调用StudentMapper方法,与数据库连接并获取数据,在取到数据后,把数据往Memcache服务中保存一份。
3.在终端telnet localhost 11211连接上Memcache服务后,如果想查看当前的Memcache中具体缓存了什么数据,方法:
3.1 命令:stats
结果:STAT curr_items 2
含义:可以知道当前一共有多少条数据
3.2 命令:stats items
结果:STAT items:1:number 2
STAT items:1:age 26
作用:记住items:后面的那个数字(就是上面的那个1),待会有用
3.3 命令:stats cachedump 1 0 (注意,这句命令里面的1就是上面的那个1,第2个参数为列出的长度,0为全部列出)
结果:ITEM age [2 b; 1461155136 s]
ITEM name [8 b; 1461155136 s]
作用:看,ITEM后面跟着的就是key
3.4 命令:get key (利用第三步得出的key,一个一个get,就能得到value)
4.总结一下Memcache中flushAll函数相关的东西
当调用了MemcachedClient的flushAll函数后,会把Memcache中的缓存数据全部删除,注意这里的删除只是标记为删除,并不等同于delete函数。假如原本的Memcache中缓存了3条数据,在telnet终端输入stats命令,可以看到durr_items为3,然后调用flushAll函数,再在telnet终端输入stats命令,会发现curr_items仍为3,使用stats cachedump命令也仍然可以看到这3个键值对的键名,但是get <key>却不会返回value了,因为这3对键值对已经被删除了。这一点不同于delete,使用delete函数就直接把键值对删得干干净净了。
这里还有一个小的细节,就是,如果我打开一个home页面,这个home页面有两个数据,我把这两个数据放入了Memcache中,当我由home页面跳转到一个flushAll页面后,我会调用一下flushAll函数,清空Memcache中的键值对,然后我点击浏览器左上角的回退箭头“<-”,返回到home页面,此时,home页面中的那两个数据依然正常显示,但是Memcache中却无法get到这两个数据。这是因为回退键“<-”只是调出了浏览器中缓存的页面,并没有重新发送请求,页面中的数据是以前存在浏览器自己的缓存中的。
【出现的问题(已解决)】
1.启动Memcache失败,错误提示:telnet: Unable to connect to remote host: Connection refused
原因:命令写错
解决办法:在终端启动Memcache时,千万要注意p的大小写区分,小写p:-p是设置Memcache监听的端口;大写P:-P是设置保存Memcache的pid文件。
2.昨天一天都没能解决的BUG,今天两分钟给搞定了。这是一个很愚蠢的BUG。
BUG描述:我正确配置了Memcache文件,正确编写了MemcachedUtil类,但是在启动项目后,调用这个类时发现MemcachedUtil.set("key","value")总是返回一个false,无论怎么改配置都不行。
原因:我只是启动了项目,并没有开启Memcache服务,当然会返回false。
解决办法:在启动项目前,应该先开启Memcache服务,要注意,你开启的Memcache服务的IP和端口号要和项目中配置的Memcached一致。
一点反思:我在编写memcache.properties时,就有过一个疑问,我在想memcached.server这个属性难道是随便写都可以吗?就是随便写一个IP和端口都行吗?如果这样的话,那我写一个别人服务器的IP,不就能把这些缓存存放到别人的服务器里面了吗?所以我感觉关于这个属性应该有一个限定什么的,现在看来,这个限定就是你首先要能在该IP上启动一个Memcache服务。
【出现的问题(未解决)】
【疑问】
1.在应用Memcache时,我发现一个问题。因为我要通过键值对的形式把数据存入缓存中,而键的类型只能为String。以查找Student数据为例,考虑以下情况:
未使用Memcache时:我所有查找数据的参数基本都是Student类型,前台给了我一个id,我会先新建一个Student类,然后student.setId(id),把这个id存入student类中,然后StudentMapper.findById(Studnet student);这样就能返回我要查找的student类了;前台给了我一个name,我也是先把name存入student类再查找的。
使用Memcache后:我得从缓存中通过键值对的形式获得数据,如果前台给了我一个id,我从数据库中获得了这个student数据(假设为s1),然后我会使用set("id",s1)保存数据到缓存中;当前台给了我一个name(这个name正好就是s1的name),我不能从缓存中get到s1数据,只能又从数据库中查找出s1,然后又set("name",s1)保存数据到缓存中。假如这个s1有十几个属性,每个属性都有可能被前台传过来作为条件查询,那我岂不是会在缓存中保存十几个s1数据?这样会不会浪费大量内存啊?
2.老大,我想把Memcache.get返回的Object类型转换为List<T>类型,有什么好的办法吗?我用的是强制转换,直接(List<T>)Memcached.get(key);但是这样会报一个警告,虽然没什么影响,但总觉得不太安全。
3.老大,我现在已经能够灵活使用Memcache的函数了,也能够在查找数据时,把数据存入缓存中了,我想了一下,不能只是在页面查找数据时,调用MemcachedClient,如果页面对数据库发生了修改(增删改),也应该相应的对缓存内容进行修改。我想了一下,有两种方案:
3.1 第一种就是,当发生增删改时,直接调用flushAll函数,把Memcache中的缓存数据全部删除,这样写起代码来很方便,每个函数加一条语句就搞定了,缺点是会错杀无辜,把那些没有发生修改的数据也删掉了。
3.2 另一种就是,针对不同的方法,制定不同的方案,如果是updateById方法,就根据id重新set数据进去。但是这样有个问题就是,很容易就会有疏漏,像delete方法,从数据库中删除了一条记录,那么在Memcache中不只是与这条记录有关的缓存需要修改,而且还有那些有关记录总数totalCount等的记录也应该发生变化,这样就容易考虑不周,产生疏漏。
实际项目中大部分是采用哪个方案呢?
评论