一、抓取策略。

  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. Spring MVC 处理静态资源不能访问问题

    在web.xml文件中加入如下代码: <servlet-mapping> <servlet-name>default</servlet-name> <url- ...

  2. 【CF 710F】String Set Queries

    在校内OJ上A了,没有加强制在线的东西..不放链接了. 这道题题意是维护一个字符串集合,支持三种操作: 1.加字符串 2.删字符串 3.查询集合中的所有字符串在给出的模板串中出现的次数 操作数\(m ...

  3. ubuntu中 不同JDK版本之间的切换

    Ubuntu中JDK 的切换前提是同时安装了多个版本,如jdk7和jdk8,若要切换,在终端输入: sudo update-alternatives --config java sudo update ...

  4. bzoj 1031 [JSOI2007]字符加密Cipher

    求出来后缀数组的rank就行了,不会可以去看集训队论文. #include<iostream> #include<cstdio> #include<cstring> ...

  5. 【CityHunter】游戏进度总控,及需求设计

    需求列表 序号 标题 描述 进度 更新日期 1 游戏主界面 游戏进入的主操作界面,     2 基础定位功能 实现自身定位功能,     3 特殊地点的Marker 搜索周边银行(资产保护).医院(状 ...

  6. java 判断String 是否为空

    StringUtils.isBlank(null) = true StringUtils.isBlank("") = true StringUtils.isBlank(" ...

  7. Development of large-scale site performance optimization method from LiveJournal background

    A LiveJournal course of development is a project in the 99 years began in the campus, a few people d ...

  8. MySQL show processlist命令详解

    show processlist; 命令的输出结果显示了有哪些线程在运行,可以帮助识别出有问题的查询语句,两种方式使用这个命令. 方式1:进入mysql/bin目录下输入mysqladmin proc ...

  9. C#常用类库(100多个)

    http://download.csdn.net/download/dxf1213cs/8238153

  10. Gossip算法

    Gossip算法因为Cassandra而名声大噪,Gossip看似简单,但要真正弄清楚其本质远没看起来那么容易.为了寻求Gossip的本质,下面的内容主要参考Gossip的原始论文:<<E ...