`

第十四章 缓存的使用

阅读更多
缓存的使用
我们先来模拟一个缓存的机制
以查询学生为示例:
public class Test {

public static void main(String[] args) throws Exception {
MyClassDao myClassDao = new MyClassDao();
StudentDao studentDao = new StudentDao();

Student student = studentDao.findById("4028810027d8be080127d8be0d790002");
System.out.println(student.getName());
Student student2 = studentDao.findById("4028810027d8be080127d8be0d790002");
System.out.println(student2.getName());
}
}
可以看到控制台输出:



很明显的看到执行了两条SQL语句,感觉有点浪费资源,如果我们把第一次查询的结果保存起来,当第二次查询的时候,先看保存了没有,如果有,直接用,如果没有,则再查询数据库.这样就更好一些.

修改StudentDao层,给Dao类增加一个模拟的缓存集合
public class StudentDao {
public static Map<String, Student> cache = new HashMap<String, Student>();

public void create(Student student) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.save(student);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}

public void delete(Student student) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.delete(student);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}

public Student findById(Serializable id) throws Exception {
Session session = null;
Transaction transaction = null;
Student student = null;

String key = Student.class.getName() + id;
student = cache.get(key);
if (student != null) {
return student;
}
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
student = (Student) session.get(Student.class, id);
cache.put(key, student);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
return student;
}
}
再一次执行Test的main方法,可以看到结果如下:



只执行了一次查询,这就是缓存的一个作用,但是缓存机制远远不会这么简单,想一下,如果在两次查询之间,对象更新了怎么办,这就涉及到缓存的更新.我们暂时只需要了解一下缓存的机制与简单的实现.因为这一块已经有现成的包和类直接用,不需要我们再从头开发.

缓存的作用主要是用来提高性能,可以简单的理解成一个Map,使用缓存涉及到三个操作:
 把数据放入缓存
 从缓存中获取数据
 删除缓存中无效数据

一级缓存: Session级共享,此缓存只能在session关闭之前使用.
save, update, saveOrUpdate, get, list, iterate, lock这些方法都会将对象放在一级缓存中, 一级缓存不能控制缓存的数量, 所以要注意大批量操作数据时可能造成内在溢出, 可以用evict, clear方法清除缓存中的内容.后面讲到Hibernate批量增加数据时再演示.
看下面的代码:
public Student findById(Serializable id) throws Exception {
Session session = null;
Transaction transaction = null;
Student student = null;

try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
student = (Student) session.get(Student.class, id);
System.out.println(student.getName());
Student student1 = (Student) session.get(Student.class, id);
System.out.println(student1.getName());
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
return student;
}
可以看到上面的代码中,只查询了一次数据库,但是缓存的作用域太小,没有太大的作用.

二级缓存: SessionFactory级共享
实现为可插拔,通过修改两个开关来改变.
告诉Hibernate,我现在要使用缓存机制:
<property name="hibernate.cache.use_second_level_cache">true</property>
配置二级缓存的提供者,也就是具体厂商提供的实现类<property name="cache.provider_class">

缓存的配置,可以在Hibernate源码包下查找hibernate.properties这个文件,找到Second-level Cache这一块,可以看到所有的配置项

可以看到缓存的实现有很多种,那么怎么选择呢?
#hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider
hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider

这需要看你的jar包中有哪个对应的缓存实现包,我们可以看到我们的Hibernate库下



可以看到有一个ehcache-1.2.3.jar包,那么这个时候,我们可以选择使用org.hibernate.cache.EhCacheProvider这个实现类,
我们可以在我们的Hibernate.cfg.xml中加入下面的配置项.
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>

接下来,我们还需要告诉Hibernate哪些类需要缓存,还需要在Hibernate.cfg.xml中加入下面的配置项.
<class-cache usage="read-only" class="chapter1.model.Student"/>
usage="read-only"指缓存的策略,有以下几种策略:



read-only是不允许修改缓存,效率最高,通常用到像新闻的分类啊,省市联动等等一些不会改变的信息.
像经常需要改动的,可以使用read-write策略,此策略是线程同步
nonstrict-read-write策略和上面一样,但是线程不同步.
transactional事务策略,如果产生错误,缓存会回滚,实现非常复杂.

还有一种方式配置告诉Hibernate哪些类需要缓存, 不需要在Hibernate.cfg.xml配置,直接在Student.hbm.xml中配置即可(推荐方法)
<class name="chapter1.model.Student" table="students">
<cache usage="read-only" />
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="uuid.hex" />
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<many-to-one name="myClass" class="chapter1.model.MyClass">
<column name="student_id" length="32" />
</many-to-one>
</class>
在id前面加上<cache usage="read-only" />, 这就不需要告诉类名了.再次执行Test类的main方法,可以看到只执行了一条SQL语句

Query的查询缓存
首先打开
<property name="hibernate.cache.use_query_cache">true</property>

修改StudentDao层,添加一个findAll()方法
public List<Student> findAll() throws Exception {
Session session = null;
Transaction transaction = null;
List<Student> students = null;

try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
Query query = session.createQuery("from Student");
query.setCacheable(true);
students = query.list();
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
return students;
}
注意这里有一句query.setCacheable(true);//设置缓存开关,使其起作用
再来执行Test的main方法:
public class Test {
public static void main(String[] args) throws Exception {
MyClassDao myClassDao = new MyClassDao();
StudentDao studentDao = new StudentDao();
List<Student> students1 = studentDao.findAll();
List<Student> students2 = studentDao.findAll();
}
}
可以看到只执行了一句select语句.

 查询的击中
执行下面的代码:
List<Student> students1 = studentDao.findAll();
System.out.println("查询所有学生");
for (Student s : students1) {
System.out.println(s.getName());
}

Student student = studentDao.findById("4028810027d8be080127d8be0d790003");
System.out.println(student.getName());
可以看到只执行了一条SQL语句, studentDao.findById("4028810027d8be080127d8be0d790003");这句代码的查询并没有执行.当Hibernate执行完了Query query = session.createQuery("from Student")类似于这种查询以后,会将查询结果存放起来,Hibernate存放的时候会这样存放map.put(“复杂的key值”, 对象的Id),所以当你执行按ID查询时,就会先从缓存中查询,这时就会被命中了.

使用缓存时需要注意的几点地方:
 读取次数大于修改次数,即不是经常修改的数据进行缓存
 缓存的容量不能大于内存
 对数据要有独享的控制权,即只能通过我这里操作数据,不能从其它通道操作数据
 可以容忍无效的数据出现
  • 大小: 2.5 KB
  • 大小: 8.4 KB
  • 大小: 15.3 KB
  • 大小: 14 KB
分享到:
评论

相关推荐

    决战Nginx系统卷:高性能Web服务器详解与运维第二部分(保证能用)

    第14章 配置FLV服务器 第15章 Nginx的访问控制 第16章 提供FTP下载 第17章 Nginx与编码 第18章 网页压缩传输 第19章 控制Nginx如何记录日志 第20章 map模块的使用 第21章 Nginx预防应用层DDoS攻击 第22章 为...

    决战Nginx: 系统卷 - 高性能Web服务器详解与运维第三部分(保证能用)

    第14章 配置FLV服务器 第15章 Nginx的访问控制 第16章 提供FTP下载 第17章 Nginx与编码 第18章 网页压缩传输 第19章 控制Nginx如何记录日志 第20章 map模块的使用 第21章 Nginx预防应用层DDoS攻击 第22章 为...

    决战Nginx系统卷:高性能Web服务器详解与运维第一部分(保证能用)

    第14章 配置FLV服务器 第15章 Nginx的访问控制 第16章 提供FTP下载 第17章 Nginx与编码 第18章 网页压缩传输 第19章 控制Nginx如何记录日志 第20章 map模块的使用 第21章 Nginx预防应用层DDoS攻击 第22章 为...

    Shiro学习教程源代码

    第十四章 SSL 第十五章 单点登录 第十六章 综合实例 第十七章 OAuth2集成 第十八章 并发登录人数控制 第十九章 动态URL权限控制 第二十章 无状态Web应用集成 第二十一章 授予身份及切换身份 第二十二章 集成验证码 ...

    第四十四章:Memcached高性能对象缓存1

    2.Redis:是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API 3.MongoD

    The Django Book(第一版 中文高清版)

    第十四章 集成的子框架 第十五章 中间件 第十六章 集成已有数据库和应用 第十七章 解读Django的管理界面 第十八章 国际化 第十九章 安全 第二十章 部署Django 附录A 案例学习 附录B 数据模型定义参考 附录C ...

    完整版Java web开发教程PPT课件 Java开发进阶教程 第20章 数据库连接池,缓存(共15页).pptx

    完整版Java web开发教程PPT课件 Java开发进阶教程 第14章 spring mvc介绍,原理以及搭建(共15页).pptx 完整版Java web开发教程PPT课件 Java开发进阶教程 第15章 spring mvc核心对象拦截器(共26页).pptx 完整版...

    The-Django-Book中文版

    第十四章: 会话、用户和注册 阅读 14 第十五章: 缓存机制 阅读 15 第十四章 集成的子框架 django.contrib 阅读 16 第十七章: 中间件 阅读 17 第十八章: 集成已有的数据库和应用 阅读 18 第十九章: 国际化 阅读 ...

    Django Web框架入门到精通 中文版

    本书所讲的是Django:一个可以使Web开发工作...第十四章: 会话、用户和注册 第十五章: 缓存机制 第十六章 集成的子框架 第十七章: 中间件 第十八章: 集成已有的数据库和应用 第十九章: 国际化 第二十章: 安全

    JAVA核心知识点全集

    RabbitMQ、第十三章:Hbase、第十四章:MongoDB、第十五章:Cassandra、第十六章:设计模式、第十七章:负载均衡、第十八章:数据库、第十九章:一致性算法、第二十章:JAVA算法、第二十一章:数据结构、第二十二章...

    Django_中文教程.rar

    Django book 2.0 的中文...第十四章: 会话、用户和注册 第十五章: 缓存机制 第十六章: 集成的子框架 django.contrib 第十七章: 中间件 第十八章: 集成已有的数据库和应用 第十九章: 国际化 第二十章: 安全

    python django建站教程

    第十四章: 会话、用户和注册 第十五章: 缓存机制 第十六章 集成的子框架 django.contrib 第十七章: 中间件 第十八章: 集成已有的数据库和应用 第十九章: 国际化 第二十章: 安全

    Djangobook2中文版.

    15. 第十四章:会话、用户和注册 16. 第十五章:缓存机制 17. 第十六章:集成的子框架 django.contrib 18. 第十七章:中间件 19. 第十八章:集成已有的数据库和应用 20. 第十九章:国际化 21. 第二十章:安全 ...

    零基础学ASP.NET.2.0(PPT 迅速入门)

    第1章 认识ASP.NET 2 ...第14章 数据源控件访问数据库 第15章 数据绑定控件显示数据 第16章 文件处理 第17章 数据缓存 第18章 ASP.NET 2. 第19章 创建Web服务 第20章 ASP.NET 2. 第21章 用ASP.NET 2

    django从入门到深入WEB教程

    第十四章 集成的子框架 第十五章 中间件 完成度 第十六章 集成已有数据库和应用 第十七章 解读Django的管理界面 第十八章 国际化 第十九章 安全 第二十章 部署Django 附录A 案例学习 附录B 数据模型定义参考 附录C ...

    深入理解linux内核第三版中文版.part3.rar

    第十四章块设备驱动程序 第十五章页高速缓存 第十六章访问文件 第十七章回收页框 第十八章Ext2和Ext3文件系统 第十九章进程通信 第二十章程序的执行 附录一 系统启动 附录二 模块 参考文献 源代码索引

    深入理解linux内核第三版中文版.part4.rar

    第十四章块设备驱动程序 第十五章页高速缓存 第十六章访问文件 第十七章回收页框 第十八章Ext2和Ext3文件系统 第十九章进程通信 第二十章程序的执行 附录一 系统启动 附录二 模块 参考文献 源代码索引

    深入理解linux内核第三版中文版.part6.rar

    第十四章块设备驱动程序 第十五章页高速缓存 第十六章访问文件 第十七章回收页框 第十八章Ext2和Ext3文件系统 第十九章进程通信 第二十章程序的执行 附录一 系统启动 附录二 模块 参考文献 源代码索引

    MVC4web编程

    ASP.NET MVC 4 Web编程 目录: 第1章:ASP.NET MVC基础 ...第14章:高级路由 第15章:可复用UI组件 第16章:日志 第17章:自动测试 第18章:自动化生成 第19章:部署 附录A ASP.NET MVC与Web Form集成

    深入理解Linux内核(第14-17章)_第三版_中文版

    《深入理解Linux内核》第三版 中文版 第十四章 块设备驱动程序 第十五章 页调高速缓存 第十六章 访问文件 第十七章 回收页框

Global site tag (gtag.js) - Google Analytics