一、抓取策略。

  1.hibernate中提供了三种抓取策略。

    (1)连接抓取(Join Fetch):这种抓取方式是默认的抓取方式。使用这种抓取方式hibernate会在select中内连接的方式获取对象的关联对象或者关联集合。

    (2)查询抓取(select Fetch):这种抓取方式会另外发送一条select语句抓取当前对象的关联实体或者集合。除非指定lazy=false,否则只有在真正访问关联关系的时候才会执行第二条select语句。

    (3)子查询抓取(subselect Fetch):另外发送一条select语句抓取在前面查询到的所有实体对象的关联集合。除非指定lazy=false,否则只有在真正访问关联关系的时候才会执行第二条select语句。

  2.案例,获取选修了课程号为1或者2的所有学生信息。

    结果表明,如果使用select或者join,则效率相同,发送的sql语句完全相同;如果使用subselect的话,效率要高很多,只需要两条sql语句。

 package com.kdyzm.fetchtest;

 import java.util.List;
import java.util.Set; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test; import com.kdyzm.hibernate.domain.Course;
import com.kdyzm.hibernate.domain.Student; public class FetchTest {
private static SessionFactory sessionFactory;
static{
Configuration configuration=new Configuration();
configuration.configure();
sessionFactory=configuration.buildSessionFactory();
}
/*
* n+1条查询是显著的特点。
*/
@Test
public void baseTest(){
Session session=sessionFactory.openSession();
List<Student>students=session.createQuery("from Student").list();
for(Student student:students){
Set<Course>courses=student.getCourses();
for(Course course:courses){
System.out.println(course);
}
}
session.close();
} /*
* 查询班级cid为1,3的所有学生
*
* 如果需要用到子查询一般就是用subselect(fetch属性值)
* 使用subselect只需要两条SQL语句。
*
*/
@Test
public void test2(){
Session session=sessionFactory.openSession();
List<Course>courses=session.createQuery("from Course where cid in(1,3)").list();
for(Course course:courses){
Set<Student>students=course.getStudents();
for(Student student:students){
System.out.println(student);
}
}
session.close();
} /*
* 总结:以上的需求中,使用select和join方法效率相同,使用子查询subselect效率最高。
*/ }

FetchTest.java

二、二级缓存

  1.二级缓存hibernate没有提供解决方案,必须借助第三方插件实现。

  2.二级缓存常见的缓存策略提供商:

Cache

Provider class

Type

Cluster Safe

Query Cache Supported

Hashtable (not intended for production use)

org.hibernate.cache.HashtableCacheProvider

memory

yes

EHCache

org.hibernate.cache.EhCacheProvider

memory,disk

yes

OSCache

org.hibernate.cache.OSCacheProvider

memory,disk

yes

SwarmCache

org.hibernate.cache.SwarmCacheProvider

clustered (ip multicast)

yes (clustered invalidation)

JBoss Cache 1.x

org.hibernate.cache.TreeCacheProvider

clustered (ip multicast), transactional

yes (replication)

yes (clock sync req.)

JBoss Cache 2

org.hibernate.cache.jbc.JBossCacheRegionFactory

clustered (ip multicast), transactional

yes (replication or invalidation)

yes (clock sync req.)

  3.二级缓存存放的是共享缓存,在二级缓存中存放的是共享数据

  4.什么时候使用二级缓存

    (1)修改不是非常频繁

    (2)可以公开的数据,如省市等

    (3)很多模块都要用到

  5.二级缓存保存在SessionFactory对象中,其生命周期和SessionFactory相同。

  6.以Ehcache为例说明二级缓存的配置和使用过程

    (1)首先去官网下载jar包:http://www.ehcache.org/,并将jar包导入项目中

     (2)在hibernate.cfg.xml文件中配置启用二级缓存:

    <property name="hibernate.cache.use_second_level_cache">
true
  </property>

    (3)在hibernate.cfg.xml配置文件中指定缓存策略提供商

    <property name="cache.provider_class">
org.hibernate.cache.EhCacheProvider
  </property>

    (4)在映射文件中指定使用二级缓存的类或集合或者在配置文件中配置使用二级缓存的类或集合。

        * 推荐在配置文件下声明使用二级缓存的类或者集合。

        在配置文件中声明:

    <class-cache usage="read-only" class="com.kdyzm.hibernate.domain.Student"/>
<collection-cache usage="read-only" collection="com.kdyzm.hibernate.domain.Student.courses"/>

    (5)在classpath根目录下新建一个文件名为ehcache.xml的文件:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="secondCache"/>
<defaultCache
name=""
maxElementsInMemory="1"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
diskPersistent="false"
/>
</ehcache>

      关于这段代码的意思稍后作解释。

    (6)配置完成,对代码进行测试

 public void testOne(){
Session session=sessionFactory.openSession();
Student student1=(Student) session.get(Student.class, 1L);
Student student2=(Student) session.get(Student.class, 2L);
Student student3=(Student)session.get(Student.class, 3L);
Student student4=(Student)session.get(Student.class, 4L); /**
* 这里加上延迟的作用是什么
*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
session.close();
}

    (7)测试结果:控制台打印结果和配置二级缓冲之前完全相同,但是在项目根目录下,新建了一个文件夹,文件夹名称为secondCache,里面有两个文件:

    

    两个文件分别是类缓存和类中的集合缓存,打开文件之后发现差不多有三个元素:

    

  7.详解配置过程中的相关问题

    (1)为什么是类和集合分别在二级缓存中存储?

      二级缓存只能缓存类中的普通属性,默认不缓存类中的集合属性,想要缓存类中的集合属性,需要在配置文件中特别说明,这样就会在二级缓存中对类中的集合属性单独存储了。所以当二级缓存中允许存在的对象数量达到上限的时候,类的实例会保存到磁盘上,同时类中的集合属性值作为对象也会保存到磁盘上,所以在测试中缓存文件夹中会出现两个文件。

    (2)ehcache.xml配置文件配置参数详解

      * ehcache标签:根标签。

      * diskStore 标签:指定缓冲文件保存的位置;如果指定具体路径的话将会使用该路径保存缓冲文件,该路径一定是个文件夹的路径,否则会报错,如果路径不存在,则会创建相应的文件夹路径直到符合条件;如果没有指定盘符,则默认就是当前工程的根目录,以上例子中使用的就是这种方法。

      * defaultCache 标签:指定二级缓存使用的各项参数。

        name属性:缓存的名称,它的取值为类的全限定名或者类的集合的名字

        maxElementsInMemory:该对象允许在内存中存在的最大数量,如果超出该限制,就使用策略解决超出限制的对象(如保存到硬盘)。

        external:设置对象是否为永久的,true表示为永久对象,这时候将会忽略timeToIdleSeconds和timeToLiveSeconds两个属性的设置;默认值是false。

        timeToIdleSeconds:设置对象空闲的最长时间,以秒为单位,超过这个时间,对象过期。当对象过期的时候,EHCache将会讲该对象在缓存中清除。如果该值为0,则表示该对象能够无限制的处于空闲状态。

        timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。如果该值为0,则表示该对象能够无限制的存在于二级缓存中,该属性值必须大于或者等于timeToIdleSeconds属性值。

        overflowToDisk:设置当缓存中的对象数量达到上限之后,是否把溢出的对象写到基于硬盘的缓存中。

        diskPersistent:当jvm结束的时候是否持久化对象,默认值是false。

        diskExpiryThreadIntervalSeconds:指定专门用于清除过期对象的监听线程的轮询时间。

    (3)使用Thread.sleep方法增加延迟的作用是什么?

      为了防止溢出的对象写入文件之前程序结束,需要给写入程序足够的时间将溢出的对象保存到磁盘中,Thread.sleep方法就是发挥着这种作用。

  8.二级缓存的各项操作

    (1)测试二级缓存:当session关闭之后,Hibernate的一级缓存也就消失了,这个时候再查询相同的数据,肯定会发出SQL语句;但是如果当前对象已经保存到了二级缓存中,session关闭,但是二级缓存并没有消失,所以这个时候再查询相同的数据,也不会发出SQL语句。

      注意:这里调用的是close方法,而不是clear方法,clear方法会将一级缓存和二级缓存全部清空!

public void testGet(){
Session session =sessionFactory.openSession(); Student student=(Student)session.get(Student.class, 1L);
System.out.println(student);
session.close();//session关闭之后一级缓存消失,但是二级缓存仍然存在!
session=sessionFactory.openSession();
Student student2=(Student)session.get(Student.class, 1L);
System.out.println(student2); session.close();
}

    结果是,只有第一次的get方法发出了SQL语句,第二次调用的get方法并没有发出SQL语句。

Hibernate: select student0_.sid as sid2_1_, student0_.sname as sname2_1_, courses1_.sid as sid2_3_, course2_.cid as cid3_, course2_.cid as cid0_0_, course2_.cname as cname0_0_ from test.stu student0_ left outer join course_stu courses1_ on student0_.sid=courses1_.sid left outer join test.course course2_ on courses1_.cid=course2_.cid where student0_.sid=?
Student [sid=1, sname=张三]
Student [sid=1, sname=张三]

    (2)把数据同步到二级缓存:测试对对象的操作,会将对对象的操作同步到二级缓存中。

        进行该项测试的时候,首先应当修改配置文件,将对Student对象的操作修改为read-write,否则会直接报异常。

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="connection.username">root</property>
<property name="connection.password">5a6f38</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/test
</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="javax.persistence.validation.mode">none</property>
<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">
true
</property>
<!-- 最后是映射文件的注册 -->
<!-- 使用的二级缓存策略提供商 -->
<property name="cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
<mapping resource="com/kdyzm/hibernate/config/Course.hbm.xml" />
<mapping resource="com/kdyzm/hibernate/config/Student.hbm.xml" />
<!-- 声明使用二级缓存的类和集合 -->
<class-cache usage="read-write" class="com.kdyzm.hibernate.domain.Student"/>
<collection-cache usage="read-only" collection="com.kdyzm.hibernate.domain.Student.courses"/>
</session-factory>
</hibernate-configuration>

hibernate.cfg.xml

        测试代码:

public void test2(){
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
Student student=(Student)session.get(Student.class, 1L);
System.out.println(student);
student.setSname("新学生!");
transaction.commit();//执行commit操作的时候会将数据同时更新到二级缓存。
session.close();//关闭session,一级缓存消失了,但是二级缓存仍然存在!
//如果调用clear方法的话,则会将一级缓存和二级缓存都清空掉!
session=sessionFactory.openSession();
Student student2=(Student)session.get(Student.class, 1L);
System.out.println(student2);
session.close();
}

      结果:

        预计结果是应当只有两次查询,一次是获取,一次是更新。
        更新完成之后的获取不应当再发出SQL语句,结果表明预测是正确的。

Hibernate: select student0_.sid as sid2_1_, student0_.sname as sname2_1_, courses1_.sid as sid2_3_, course2_.cid as cid3_, course2_.cid as cid0_0_, course2_.cname as cname0_0_ from test.stu student0_ left outer join course_stu courses1_ on student0_.sid=courses1_.sid left outer join test.course course2_ on courses1_.cid=course2_.cid where student0_.sid=?
Student [sid=1, sname=张三]
Hibernate: update test.stu set sname=? where sid=?
Student [sid=1, sname=新学生!]

      结论:调用commit方法的时候,同时将二级缓存中的数据更新掉了,但是这个时候必须对配置文件进行修改,使得能对二级缓存中的对象进行修改。

三、HQL语言

  1.HQL是Hibernate Query Language的缩写,它是面向对象的查询语言,和SQL语言有些相似,在Hibernate提供的各种检索方式中,HQL是使用最为广泛的一种检索方式。

  2.HQL的功能

    (1)在查询语句中设定各种查询条件

    (2)支持投影查询,即仅仅检索出部分对象的属性

    (3)支持分页查询

    (4)支持连接查询

    (5)支持分组查询,允许使用having和group by关键字。

    (6)提供内置聚集函数,如sum(),min(),和max()等。

    (7)能够调用用户自定义的函数或者标准的SQL函数。

    (8)支持子查询

    (9)支持动态绑定函数

  3.HQL的练习操作

    (1)最简单的对单表的查询操作

    public void testOne(){
Session session=sessionFactory.openSession();
Query query=session.createQuery("from Student where sid='1'");
List<Student>students=query.list();
for(Student student:students){
System.out.println(student);
}
session.close();
}

    (2)详情查看3.6.5的文档第16章。

练习的源代码:https://github.com/kdyzm/day44_hibernate03

【Java EE 学习 48】【Hibernate学习第五天】【抓取策略】【二级缓存】【HQL】的更多相关文章

  1. hibernate detached分离查询 与 抓取策略注意事项

    1.detached在抓取策略为 jion显式左外连接查询情况下 会产生笛卡儿积现象 DetachedCriteria dc = DetachedCriteria.forClass(Topic.cla ...

  2. 【转】Hibernate 原汁原味的四种抓取策略

    最近在研究 Hibernate 的性能优化的时候碰到了"抓取策略", 由于以前没有详细的研究过, 所以到处找资料, 但是无论从一些讲 Hibernate 书籍,还是他人 Blog ...

  3. Hibernate 原汁原味的四种抓取策略(转)

    原文出处:http://www.cnblogs.com/rongxh7/archive/2010/05/12/1733088.html     尊重原作者,访问原创地址 最近在研究 Hibernate ...

  4. 【Hibernate 8】Hibernate的调优方法:抓取策略

    在上一篇博客中,介绍了Hibernate的缓存机制.合理的配置缓存,可以极大程度上优化Hibernate的性能.这篇博客,介绍另外一个调优方式:抓取策略. 一.什么是抓取策略 抓取策略(fetchin ...

  5. Hibernate学习---第十一节:Hibernate之数据抓取策略&批量抓取

    1.hibernate 也可以通过标准的 SQL 进行查询 (1).将SQL查询写在 java 代码中 /** * 查询所有 */ @Test public void testQuery(){ // ...

  6. Hibernate学习笔记(八) — 懒载入与抓取策略

    懒载入(Load On Demand)是一种独特而又强大的数据获取方法,它可以在用户滚动页面的时候自己主动获取很多其它的数据,而新得到的数据不会影响原有数据的显示,同一时候最大程度上降低server端 ...

  7. 【Hibernate学习】 —— 抓取策略(注解方式)

    当应用程序须要在关联关系间进行导航的时候.hibernate怎样获取关联对象的策略. 抓取策略的方式: FetchType.LAZY:懒载入.载入一个实体时.定义懒载入的属性不会立即从数据库中载入. ...

  8. Java三大框架之——Hibernate中的三种数据持久状态和缓存机制

    Hibernate中的三种状态   瞬时状态:刚创建的对象还没有被Session持久化.缓存中不存在这个对象的数据并且数据库中没有这个对象对应的数据为瞬时状态这个时候是没有OID. 持久状态:对象经过 ...

  9. python3.4学习笔记(十七) 网络爬虫使用Beautifulsoup4抓取内容

    python3.4学习笔记(十七) 网络爬虫使用Beautifulsoup4抓取内容 Beautiful Soup 是用Python写的一个HTML/XML的解析器,它可以很好的处理不规范标记并生成剖 ...

随机推荐

  1. UI: 概述, 启动屏幕, 屏幕方向

    UI 设计概述 启动屏幕(闪屏) 屏幕方向 示例1.UI 设计概述UI/Summary.xaml <Page x:Class="Windows10.UI.Summary" x ...

  2. 教你一招:解决安装或卸载office时 提示错误2503 2502 发生了内部错误

    问题重现: 解决办法:使用软件卸载工具 Uninstall Tool 3.5.1 中文破解版强制删除文件,非常暴力,完美解决. 解决过程一览: 工具下载地址: 软件卸载工具 Uninstall Too ...

  3. java并发编程实战(java concurrency in practice)

    第一章   线程共享进程范围内的资源,但每个线程都有各自的程序计数器.栈以及局部变量等. 多个线程可以同时调度到多个CPU上运行.   线程的优势? 在服务应用程序中,可以提升资源利用率以及系统吞吐率 ...

  4. 基于 Arduino 的 RFID 识别实验

    http://www.it165.net/embed/html/201512/3287.html 2015年12月04日(周五) 上午  博士的智能卡实验--RFID识别实验,基于51单片机: 我们的 ...

  5. Kakfa重连测试

    在Kafak已启动的情况下: 发送端首次连接大概耗时400毫秒.后续消息发送都在1毫秒以下. 接收端首次连接大概耗时400-7000毫秒.后续消息接收都在1毫秒以下.(具体时间与topic中存留的消息 ...

  6. A=AUB

    #include<stdio.h>#include<stdlib.h> #define LIST_MAX 10#define LIST_ADD 2 typedef struct ...

  7. Nginx下wordpress伪静态规则(rewrite)

    当我们从apache服务器转向Nginx服务器的时候,它们的伪静态规则就不一样了,所以你熟悉Nginx服务器的伪静态规则,自己写当然也好.但很多网友还是不太了解Nginx服务器的伪静态规则的,而如果你 ...

  8. @RequestMapping 用法详解之地址映射(转)

    引言: 前段时间项目中用到了RESTful模式来开发程序,但是当用POST.PUT模式提交数据时,发现服务器端接受不到提交的数据(服务器端参数绑定没有加任何注解),查看了提交方式为applicatio ...

  9. Asp.net MVC Comet推送

    一.简介 在Asp.net MVC实现的Comet推送的原理很简单. 服务器端:接收到服务器发送的AJAX请求,服务器端并不返回,而是将其Hold住,待到有东西要通知客户端时,才将这个请求返回. 客户 ...

  10. 浅谈JSON

    JSON的全称是”JavaScript Object Notation”,意思是JavaScript对象表示法,它是一种基于文本,独立于语言的轻量级数据交换格式.XML也是一种数据交换格式,为什么没有 ...