缓存(Cache)就是数据交换的缓冲区,一个临时存储数据的地方,当我们读取数据时会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话再从内存中找。
在实际开发中,我们会经常对数据库进行数据查询,而从数据库读取数据的效率是非常低下的,并且频繁地去访问数据库会增大数据库压力降低数据库查询性能等,所以我们可以将经常查询且不经常改变的数据保存到缓存中(缓存就是内存中的一个对象),这样用户在查询的时候就不用到数据库中查询(磁盘),从而减少与数据库的交付次数,从而提高查询效率,解决了高并发系统的性能问题。
缓存的本质就是用空间换时间,牺牲数据的实时性,以服务器内存中的数据暂时代替从数据库读取最新的数据,减少数据库IO,减轻服务器压力,减少网络延迟,从而提高访问速度。
一级缓存是SqlSession级别的缓存,在操作数据库时需要构造SqlSession对象,在对象中有一个 数据结构(HashMap) 用于存储缓存数据,不同的SqlSession之间的缓存数据区域(HashMap)互不影响。
当在同一个sqlSession (会话) 中执行两次相同的SQL语句时,第一次执行完毕会将从数据库中查询的数据写到缓存(内存),第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。需要注意的是,如果sqlSession执行了DML操作(insert、update、delete),并提交到数据库,MyBatis则会清空sqlSession中的一级缓存,这样做的目的是为了保证缓存中存储的是最新的信息,避免出现脏读现象。
MyBatis默认开启一级缓存,不需要进行任何配置,当一个sqlSession结束后该sqlSession的一级缓存也就不在了,一级缓存是不能关闭的。
测试说明:
我们可以创建一张学生表,写sql查询语句根据id查询学生信息,定义一个方法,在方法内调用三次该查询,提前开启日志打印方便我们在控制台查看打印的sql语句,我们可以看到,只有第一次打印了sql语句也就是真正查询了数据库,后面的查询使用了一级缓存,直接在缓存中读取的数据并没有访问数据库。
我们接着对上面的数据进行测试,从上面我们可以知道学生表中的数据已经存入到缓存中,接下来我们可以对数据进行(增/删/改)测试(insert、update、delete),再进行查询。可以发现进行了增、删、改操作后控制台打印了后面的查询sql语句,也就是再次访问了数据库进行查询,所以清空了一级缓存导致失效了。
我们继续测试,这次我们开启两个SqlSession(会话),在SqlSession1中我们进行查询操作从而开启一级缓存,在SqlSession2我们可以进行(增/删/改)操作,再用SqlSession1去查询,可以发现出现了脏数据,SqlSession1并没有查询到SqlSession2修改后的数据。所以验证了一级缓存只在数据库会话内部共享
小结:
一级缓存(本地缓存), 作用域默认为sqlSession。当 Session flush 或 close 后, 该Session 中的所有Cache 将被清空。
本地缓存不能被关闭, 但可以调用clearCache()来清空本地缓存, 或者改变缓存的作用域。
在mybatis3.1之后,可以配置本地缓存的作用域,在 mybatis.xml 中配置。
让一级缓存失效的几种情况:
① 不同的SqlSession对应不同的一级缓存
② 同一个SqlSession但是查询条件不同
③ 同一个SqlSession的两次查询期间执行了增删改操作
④ 同一个SqlSession的两次查询期间手动清空了缓存
二级缓存也叫全局缓存,一级缓存作用域太低了,二级缓存默认是全局开启的,它是基于namespace级别的缓存,一个名称空间,对应一个二级缓存,所以也称之为“namespace缓存”,需要在配置SQL语句的XML中添加节点, 以表示当前XML中的所有查询都允许开通二级缓存,并且,在节点上配置useCache=“true”,则对应的节点的查询结果将被二级缓存处理,并且,此查询返回的结果的类型必须是实现了Serializable接口的,如果使用了配置如何封装查询结果,则必须使用节点来封装主键的映射,满足以上条件后,二级缓存将可用,只要是当前namespace中查询出来的结果,都会根据所执行的SQL语句及参数进行 结果的缓存
开启二级缓存具体步骤:
在mybatis-config.xml文件中开启缓存
<!-- 全局配置参数,需要时再设置 -->
<settings>
<!-- 开启二级缓存 默认值为true -->
<setting name="cacheEnabled" value="true"/>
</settings>
在mapper.xml配置文件中使用二级缓存
<mapper namespace="com.wenjie.mapper.UserMapper">
<cache/> <!-- 二级缓存生效 -->
<select id="selectAll" resultType="user">
select *
from tb_user;
</select>
<select id="selectById" resultType="user">
select *
from tb_user where id = #{id};
</select>
</mapper>
也可以直接在mapper.xml文件中加入,但是要记得实体类要序列化,不然容易会报Caused by: java.io.NotSerializableException: com.xsq.pojo.User异常
在实体类中实现序列化:
public class User implements Serializable {
//Serializable实现序列化,为了将来反序列化
}
运行程序进行测试,控制台输出结果如下所示:

只进行了一次查询,那么就说明数据已经进入到了二级缓存中。
对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了新增、修改、删除操作后,默认该作用域下所有 select 中的缓存将被 clear。
工作机制
小结:
总结:
无论是一级缓存还是二级缓存,只要数据发生了写操作(增、删、改), 缓存数据都将被自动清理
由于Mybatis的缓存清理机制过于死板,所以,一般在开发实践中并不怎么使用!更多的是使用其它的缓存工具并自行制定缓存策略
我试过重新启动apache,缓存的页面仍然出现,所以一定有一个文件夹在某个地方。我没有“公共(public)/缓存”,那么我还应该查看哪些其他地方?是否有一个URL标志也可以触发此效果? 最佳答案 您需要触摸一个文件才能清除phusion,例如:touch/webapps/mycook/tmp/restart.txt参见docs 关于ruby-如何在Ubuntu中清除RubyPhusionPassenger的缓存?,我们在StackOverflow上找到一个类似的问题:
尝试在我的RoR应用程序中实现计数器缓存列时出现错误Unknownkey(s):counter_cache。我在这个问题中实现了模型关联:Modelassociationquestion这是我的迁移:classAddVideoVotesCountToVideos0Video.reset_column_informationVideo.find(:all).eachdo|p|p.update_attributes:videos_votes_count,p.video_votes.lengthendenddefself.downremove_column:videos,:video_vot
当我尝试进行bundle安装时,我的gem_path和gem_home指向/usr/local/rvm/gems/我没有写入权限,并且由于权限无效而失败。因此,我已将两个路径都更改为我具有写入权限的本地目录。这样做时,我进行了bundle安装,我得到:bruno@test6:~$bundleinstallFetchinggemmetadatafromhttps://rubygems.org/.........Fetchinggemmetadatafromhttps://rubygems.org/..Bundler::GemspecError:Couldnotreadgemat/afs/
我一直在Heroku上尝试不同的缓存策略,并添加了他们的memcached附加组件,目的是为我的应用程序添加Action缓存。但是,当我在我当前的应用程序上查看Rails.cache.stats时(安装了memcached并使用dalligem),在执行应该缓存的操作后,我得到current和total_items为0。在Controller的顶部,我想缓存我有的Action:caches_action:show此外,我修改了我的环境配置(对于在Heroku上运行的配置)config.cache_store=:dalli_store我是否可以查看其他一些统计数据,看看它是否有效或我做错
我有一个具有页面缓存的ControllerAction,我制作了一个清扫程序,它使用Controller和指定的Action调用expire_page...Controller操作呈现一个js.erb模板,所以我试图确保expire_page删除public/javascripts中的.js文件,但它没有这样做。classJavascriptsController"javascripts",:action=>"lol",:format=>'js')endend...所以,我访问javascripts/lol.js并呈现我的模板。我验证了public/javascripts/lol.js
我的Controller有这个:caches_action:render_ticker_for_channel,:expires_in=>30.seconds在我的路由文件中我有这个:match'/render_c_t/:channel_id'=>'render#render_ticker_for_channel',:as=>:render_channel_ticker在日志文件中我看到了这个:Writefragmentviews/mcr3.dev/render_c_t/63(11.6ms)我如何手动使它过期?我需要从与渲染Controller不同的Controller使它过期,但即使
我在开发和生产中都使用docker,真正困扰我的一件事是docker缓存的简单性。我的ruby应用程序需要bundleinstall来安装依赖项,因此我从以下Dockerfile开始:添加GemfileGemfile添加Gemfile.lockGemfile.lock运行bundleinstall--path/root/bundle所有依赖项都被缓存,并且在我添加新gem之前效果很好。即使我添加的gem只有0.5MB,从头开始安装所有应用程序gem仍然需要10-15分钟。由于依赖项文件夹的大小(大约300MB),然后再花10分钟来部署它。我在node_modules和npm上遇到了
我正在使用Capybara2.1和Ruby1.9.3,使用selenium驱动程序(带有Minitest和测试单元)来测试网络应用程序。我正在努力解决StaleElementReferenceException问题。我已经看到很多关于该主题的讨论,但我无法找到解决我所面临问题的方法。所以基本上,我试图使用以下代码在我的页面上找到所有分页元素:pagination_elements=page.all('.paginationa')然后我对这些元素做一些断言,例如:pagination_elements.first.must_have_content('1')在这些断言之后,我通过单击下一
HTTP缓存是指浏览器或者代理服务器将已经请求过的资源保存到本地,以便下次请求时能够直接从缓存中获取资源,从而减少网络请求次数,提高网页的加载速度和用户体验。缓存分为强缓存和协商缓存两种模式。一.强缓存强缓存是指浏览器直接从本地缓存中获取资源,而不需要向web服务器发出网络请求。这是因为浏览器在第一次请求资源时,服务器会在响应头中添加相关缓存的响应头,以表明该资源的缓存策略。常见的强缓存响应头如下所述:Cache-ControlCache-Control响应头是用于控制强制缓存和协商缓存的缓存策略。该响应头中的指令如下:max-age:指定该资源在本地缓存的最长有效时间,以秒为单位。例如:Ca
我正在构建一个Rails应用程序,该应用程序将基本上包含一组SOAP命令。我不想每次都获取WSDL来实现某种缓存方法,尽管我不太确定从哪里开始执行此操作。是否有特定于Rails的东西可以帮助我,或者我应该通过Ruby下载文件并加载它?只是在寻找某种总体方向...... 最佳答案 如果您使用savon然后是remoteWSDLwillbedownloadedonceperclientinstance:the(remote)WSDLhastobedownloadedandparsedonceforeveryclientandsocome