星空网 > 软件开发 > Java

Hibernate(四)

Hibernate的二级缓存

  • 理解缓存定义:
    • 缓存(Cache):计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。缓存中的数据是数据存储源中数据的拷贝。缓存的物理介质通常是内存
  • 理解二级缓存的定义:
    • Hibernate中提供了两个级别的缓存
      • 一级缓存是Session级别的缓存,它是属于事务范围的缓存。这一级别的缓存是由Hibernate管理的,一般情况下无需进行干预。
      • 二级缓存是SessionFactory级别的缓存,它是属于进程范围的缓存。
    • Hibernate的SessionFactory缓存可以分为两类:
      • 内置缓存:Hibernate自带的,不可拆卸。通常在Hibernate的初始化阶段,Hibernate会把映射元数据和预定义的SQL语句放到SessionFactory的缓存中,映射元数据是映射文件中数据(*.hbm.
      • 外置缓存(二级缓存):一个可排至的缓存插件,在默认情况下,SessionFactory不会启用这个缓存插件。外置缓存中的数据是数据库数据的复制,外置缓存的物理介质可以是内存或硬盘。
  • 使用Hibernate的二级缓存:
    • 适合放入二级缓存中的数据:
      • 很少被修改。
      • 不是很重要的数据,允许出现偶尔的并发问题。
    • 不适合放入二级缓存中的数据:
      • 经常被修改。
      • 财务数据,绝对不允许出现并发问题。
      • 与其他应用程序共享的数据。
  • Hibernate的二级缓存的架构

Hibernate(四)    

  • 二级缓存的并发访问策略:
    • 两个并发的事务同时访问吃就吃的缓存的相同数据时,也有可能出现各类并发问题。
    • 二级缓存可以设定一下4中类型的并发访问策略,每一种访问策略对应一种事务的隔离级别。
      • 非严格读写(nonstrict-read-wirte):不保证缓存与数据库中数据的一致性。提供Read Uncommited事务隔离级别。对于极少被修改,而且允许脏读的数据,可以采用这种策略。
      • 读写型read-write):提供Read Committed数据隔离级别。对于经常读但是很少被修改的数据,可以采用这种隔离烈性,因为它可以防止脏读。
      • 事务型(transaction):仅仅在受管理环境下使用。它提供了Repeatable Read 事务隔离级别。对于经常读但是很少被修改的数据,可以采用这种隔离级别,因为它可以防止脏读和不可以重复读。
      • 只读型(read-only):提供Serializable数据隔离级别。对于从来不会被修改的数据,可以采用这种访问策略。
  • 管理Hibernate的二级缓存
    • Hibernate的二级缓存是进程或集群范围内的缓存。
    • 二级缓存是可配置的插件,Hibernate允许选用以下类型的缓存插件:
      • EHCache:可作为进程分为内的缓存,存放数据的物理介质可以是内存或硬盘,对Hibernate的查询缓存提供了支持。
      • OSCache:可作为进程范围内的缓存,存放数据的物理介质可以是内存或硬盘,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持。
      • SwarmCache:可作为集群范围内的缓存,但是不支持Hibernate的查询缓存。
      • JBossCache:可作为集群范围内的缓存,支持Hibernate的查询缓存。
    • 4种缓存插件的并发访问策略
缓存插件read-onlynonstrict-read-writeread-writetransaction
EHCache 
OSCache 
SwarmCache  
JBossCache  

 

 

 

 

 

 

 

 

 

  • 使用Hibernate的二级缓存的步骤:
    • 加入二级缓存插件的jar包及配置文件。
      • backport-util-concurrent.jar
      • commons-logging.jar
      • ehcache-1.5.0.jar
      • ehcache.
    • 配置hibernate.cfg.
    • 配置启动Hibernate的二级缓存
      • <!-- 启用二级缓存 -->
        <property name="hibernate.cache.use_second_level_cache">true</property>

      • 配置二级缓存的提供商
        • <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
      • 配置那些类使用二级缓存
        • <!-- 配置那个类使用二级缓存 -->
          <class-cache usage="read-only" />

  • 二级缓存的示例:证明二级缓存的存在
    • 配置演示环境:实体类,对应的映射文件及核心配置文件
    • 实体类:
      • Customer.java
package cn.hibernate3.demo4;import java.io.Serializable;import java.util.HashSet;/** * 客户实体 */import java.util.Set;public class Customer implements Serializable{  private Integer cid;  private String cname;  //一个客户有多个订单  private Set<Order> orders = new HashSet<Order>();  public Integer getCid() {    return cid;  }  public void setCid(Integer cid) {    this.cid = cid;  }  public String getCname() {    return cname;  }  public void setCname(String cname) {    this.cname = cname;  }  public Set<Order> getOrders() {    return orders;  }  public void setOrders(Set<Order> orders) {    this.orders = orders;  }    }

      • Order.java
package cn.hibernate3.demo4;import java.io.Serializable;/** * 订单实体 */public class Order implements Serializable{  private Integer oid;  private String addr;  //订单属于某一个客户  private Customer customer ;    public Integer getOid() {    return oid;  }  public void setOid(Integer oid) {    this.oid = oid;  }  public String getAddr() {    return addr;  }  public void setAddr(String addr) {    this.addr = addr;  }  public Customer getCustomer() {    return customer;  }  public void setCustomer(Customer customer) {    this.customer = customer;  }    }

    • 映射文件:
      • Customer.hbm.
<??><!-- 引入约束 --><!DOCTYPE hibernate-mapping PUBLIC   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping>  <class name="cn.hibernate3.demo4.Customer" table="customer" lazy="true">    <!-- 配置唯一标识 -->    <id name="cid" column="cid">      <generator class="native"/>    </id>    <!-- 配置普通属性 -->    <property name="cname" column="cname" type="java.lang.String"/>    <!-- 建立映射 -->    <!-- 配置集合 -->    <!--       set标签中的name表示关联对象的属性名称             -->    <set name="orders" cascade="save-update">      <!-- key标签中的column用来一对多的多的一方的外键 -->      <key column="cno"/>      <!-- 配置一个one-to-many -->      <one-to-many class="cn.hibernate3.demo4.Order" />    </set>  </class></hibernate-mapping>

      • Order.hbm.
<??><!-- 引入约束 --><!DOCTYPE hibernate-mapping PUBLIC   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping>  <class name="cn.hibernate3.demo4.Order" table="orders">    <!-- 配置唯一标识 -->    <id name="oid" column="oid">      <generator class="native"/>    </id>    <!-- 配置普通属性 -->    <property name="addr" column="addr" type="java.lang.String"/>    <!-- 建立映射 -->    <!--       many-to-one标签        属性:          name:关联对象的属性名称。          column:表中外键的名称。          class:关联对象的全路径。     -->    <many-to-one name="customer" column="cno" class="cn.hibernate3.demo4.Customer"></many-to-one>  </class></hibernate-mapping>

    • 核心映射文件
<??><!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="hibernate.connection.driver_class">    com.mysql.jdbc.Driver  </property>  <!-- 访问数据库的url -->  <property name="hibernate.connection.url">    jdbc:mysql:///hibernate_day03  </property>  <!-- 用户名 -->  <property name="hibernate.connection.username">root</property>  <!-- 密码 -->  <property name="hibernate.connection.password">root</property>  <!-- 方言 -->  <property name="hibernate.dialect">    org.hibernate.dialect.MySQLDialect  </property>  <!-- C3P0连接池设定-->  <!-- 使用c3po连接池 配置连接池提供的供应商-->  <property name="connection.provider_class">    org.hibernate.connection.C3P0ConnectionProvider  </property>  <!--在连接池中可用的数据库连接的最少数目 -->  <property name="c3p0.min_size">5</property>  <!--在连接池中所有数据库连接的最大数目 -->  <property name="c3p0.max_size">20</property>  <!--设定数据库连接的过期时间,以秒为单位,    如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->  <property name="c3p0.timeout">120</property>  <!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->  <property name="c3p0.idle_test_period">3000</property>  <!-- 可选配置 -->  <!-- 显示SQL -->  <property name="hibernate.show_sql">true</property>  <!-- 格式化SQL -->  <property name="hibernate.format_sql">true</property>  <!-- hbm:映射 2:to ddl:create drop alter -->  <property name="hibernate.hbm2ddl.auto">update</property>  <!--     1—Read uncommitted isolation    2—Read committed isolation    4—Repeatable read isolation    8—Serializable isolation   -->  <property name="hibernate.connection.isolation">4</property>    <property name="hibernate.current_session_context_class">thread</property>    <!-- 启用二级缓存 -->  <property name="hibernate.cache.use_second_level_cache">true</property>    <!-- 配置使用的二级缓存提供商 -->  <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>        <mapping resource="cn/hibernate3/demo4/Customer.hbm. />  <mapping resource="cn/hibernate3/demo4/Order.hbm. />  <!--
  


<class-cache usage="read-write" />
<class-cache usage="read-write" />

<collection-cache usage="read-write" collection="cn.hibernate3.demo4.Customer.orders"/>




--></session-factory></hibernate-configuration>

    • 测试类
  @Test  public void demo13(){    Session session = HibernateUtils.openSession();    Transaction tx = session.beginTransaction();    Customer customer1 = (Customer) session.get(Customer.class, 1);    System.out.println(customer1.getCname());     tx.commit();            session = HibernateUtils.openSession();    tx = session.beginTransaction();    Customer customer2 = (Customer) session.get(Customer.class, 1);    System.out.println(customer2.getCname());         tx.commit();    session.close();      }

Hibernate(四)

    • 设置Customer类使用二级缓存。其核心配置文件如下:
<??><!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="hibernate.connection.driver_class">    com.mysql.jdbc.Driver  </property>  <!-- 访问数据库的url -->  <property name="hibernate.connection.url">    jdbc:mysql:///hibernate_day03  </property>  <!-- 用户名 -->  <property name="hibernate.connection.username">root</property>  <!-- 密码 -->  <property name="hibernate.connection.password">root</property>  <!-- 方言 -->  <property name="hibernate.dialect">    org.hibernate.dialect.MySQLDialect  </property>  <!-- C3P0连接池设定-->  <!-- 使用c3po连接池 配置连接池提供的供应商-->  <property name="connection.provider_class">    org.hibernate.connection.C3P0ConnectionProvider  </property>  <!--在连接池中可用的数据库连接的最少数目 -->  <property name="c3p0.min_size">5</property>  <!--在连接池中所有数据库连接的最大数目 -->  <property name="c3p0.max_size">20</property>  <!--设定数据库连接的过期时间,以秒为单位,    如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->  <property name="c3p0.timeout">120</property>  <!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->  <property name="c3p0.idle_test_period">3000</property>  <!-- 可选配置 -->  <!-- 显示SQL -->  <property name="hibernate.show_sql">true</property>  <!-- 格式化SQL -->  <property name="hibernate.format_sql">true</property>  <!-- hbm:映射 2:to ddl:create drop alter -->  <property name="hibernate.hbm2ddl.auto">update</property>  <!--     1—Read uncommitted isolation    2—Read committed isolation    4—Repeatable read isolation    8—Serializable isolation   -->  <property name="hibernate.connection.isolation">4</property>    <property name="hibernate.current_session_context_class">thread</property>    <!-- 启用二级缓存 -->  <property name="hibernate.cache.use_second_level_cache">true</property>    <!-- 配置使用的二级缓存提供商 -->  <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>        <mapping resource="cn/hibernate3/demo4/Customer.hbm. />  <mapping resource="cn/hibernate3/demo4/Order.hbm. />

  <!-- 配置那个类使用二级缓存-->
  <class-cache usage="read-write" />
  <class-cache usage="read-write" />
  <!-- 集合缓存区 -->
  <collection-cache usage="read-write" collection="cn.hibernate3.demo4.Customer.orders"/>

</session-factory></hibernate-configuration>

Hibernate(四)

 

  • 类缓存区的特点:缓存的是对象的散装的数据。
@Test  public void demo13(){    Session session = HibernateUtils.openSession();    Transaction tx = session.beginTransaction();    Customer customer1 = (Customer) session.get(Customer.class, 1);    Customer customer2 = (Customer) session.get(Customer.class, 1);    System.out.println(customer1==customer2);     tx.commit();        session = HibernateUtils.openSession();    tx = session.beginTransaction();    Customer customer3 = (Customer) session.get(Customer.class, 1);    Customer customer4 = (Customer) session.get(Customer.class, 1);    System.out.println(customer3 == customer4);        System.out.println(customer1 == customer3);        tx.commit();    session.close();      }

Hibernate(四)

  • 集合缓存区的特点:缓存的是对象的id,需要依赖类缓存区的配置。      
@Test  public void demo13(){    Session session = HibernateUtils.openSession();    Transaction tx = session.beginTransaction();    Customer customer1 = (Customer) session.get(Customer.class, 1);    System.out.println(customer1.getOrders().size());    tx.commit();        session = HibernateUtils.openSession();    tx = session.beginTransaction();    Customer custome2 = (Customer) session.get(Customer.class, 1);    System.out.println(custome2.getOrders().size());        tx.commit();    session.close();      }

Hibernate(四)

Hibernate(四)

  • list()方法和iterate()方法的区别
    • list()方法:会向二级缓存中存放数据,但是不会使用二级缓存中的数据。
      • 证明:list()方**向二级缓存中存放数据。
  @Test  //list()方**向二级缓存中存放数据,但是不会使用二级缓存中的数据  //证明list()方**向二级缓存中存放数据  public void demo13(){    Session session = HibernateUtils.openSession();    Transaction tx = session.beginTransaction();    List<Customer> list = session.createQuery("from Customer").list();//发送SQL语句    for (Customer customer : list) {      System.out.println(customer.getCname());    }        tx.commit();        session = HibernateUtils.openSession();    tx = session.beginTransaction();        Customer customer = (Customer) session.get(Customer.class, 1);//不发送SQL语句,从二级缓存中获取    System.out.println(customer.getCname());        tx.commit();    session.close();      }

Hibernate(四)

      • 证明:list()不会使用二级缓存中的数据。
  @Test  //list()方**向二级缓存中存放数据,但是不会使用二级缓存中的数据  //证明list()方法不会使用二级缓存中的数据  public void demo13(){    Session session = HibernateUtils.openSession();    Transaction tx = session.beginTransaction();    List<Customer> list = session.createQuery("from Customer").list();//发送SQL语句    for (Customer customer : list) {      System.out.println(customer.getCname());    }        tx.commit();        session = HibernateUtils.openSession();    tx = session.beginTransaction();        list = session.createQuery("from Customer").list();//发送SQL语句     for (Customer customer : list) {        System.out.println(customer.getCname());    }         tx.commit();    session.close();      }

Hibernate(四)

    • iterate()方法:
      • 和list()方法一样也能执行查询操作。
      • list()方法执行的SQL语句包含实体类对象的数据表中的所有字段。
      • iterate()方法执行SQL语句中仅包含实体类对应的数据表的id字段。
      • 当遍历结果集的时候,该方法先到session缓存及二级缓存中查看是否存在特定oid的对象,如果存在,就直接返回该对象,如果不存在,就通过相应的SQL select语句到数据库中加载特定的实体对象。
      • 大多数情况下,应考虑使用list()方法执行查询操作,iterate()方法仅在满足以下条件对的场合,可以稍微提高查询性能:
        • 要查询的数据表中包含大量的字段。
        • 启用了二级缓存,且二级缓存中可能已经包含了待查询的对象。
  @Test  public void demo13(){    Session session = HibernateUtils.openSession();    Transaction tx = session.beginTransaction();        //发送N+1条SQL去查询    Iterator<Customer> iterator = session.createQuery("from Customer").iterate();    while(iterator.hasNext()){      Customer customer = iterator.next();      System.out.println(customer.getCname());    }        tx.commit();        session = HibernateUtils.openSession();    tx = session.beginTransaction();        iterator = session.createQuery("from Customer").iterate();    while(iterator.hasNext()){      Customer customer = iterator.next();      System.out.println(customer.getCname());    }         tx.commit();    session.close();      }

Hibernate(四)

 

  •  一级缓存更新同步到二级缓存及二级缓存配置文件
    • 证明一级缓存更新同步到二级缓存
  @Test  public void demo13(){    Session session = HibernateUtils.openSession();    Transaction tx = session.beginTransaction();        Customer customer = (Customer) session.get(Customer.class, 1);    customer.setCname("哈哈");        tx.commit();        session = HibernateUtils.openSession();    tx = session.beginTransaction();        Customer customer2 = (Customer) session.get(Customer.class, 1);    System.out.println(customer2.getCname());            tx.commit();    session.close();      }

Hibernate(四)

    • 二级缓存的配置文件

Hibernate(四)

  • 更新时间戳区
  @Test  public void demo13(){    Session session = HibernateUtils.openSession();    Transaction tx = session.beginTransaction();        Customer customer = (Customer) session.get(Customer.class, 1);    session.createQuery("update Customer set cname='呵呵' where cid= 1").executeUpdate();        tx.commit();        session = HibernateUtils.openSession();    tx = session.beginTransaction();        Customer customer2 = (Customer) session.get(Customer.class, 1);    System.out.println(customer2.getCname());            tx.commit();    session.close();      }

Hibernate(四)

Hibernate(四)

  • 查询缓存区
    • 比二级缓存功能更加强大,而且查询缓存必须依赖二级缓存。
    • 二级缓存:对类或对象的缓存。
    • 查询缓存:针对类中的属性的缓存。
      • select c.cname from Customer c;
    • 查询缓存的配置
      • 前提是二级缓存已经配置完毕。
      • 在核心配置文件中配置
        • <property name="hibernate.cache.use_query_cache">true</property>
      • 编写代码的时候,添加如下代码(详解示例):
        •                  
  @Test  public void demo13(){    Session session = HibernateUtils.openSession();    Transaction tx = session.beginTransaction();        Query query = session.createQuery("select c.cname from Customer c");    query.setCacheable(true);    List<Object> list = query.list();    for (Object object : list) {      System.out.println(object);    }        tx.commit();        session = HibernateUtils.openSession();    tx = session.beginTransaction();        query = session.createQuery("select c.cname from Customer c");    query.setCacheable(true);    list = query.list();    for (Object object : list) {      System.out.println(object);    }        tx.commit();    session.close();      }  

Hibernate(四)

                 




原标题:Hibernate(四)

关键词:Hibernate

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流