hibernate二级缓存(一)一级缓存与二级缓存

hibernate二级缓存(一)一级缓存与二级缓存hibernate二级缓存(一)一级缓存与二级缓存1.hibernate一级缓存hibernate的一级缓存是session级别的缓存,一级缓存hibernate默认启用且不能被卸载,一个事务内有效。特点:使用一级缓存的目的是为了减少对数据库的访问次数,从而提升hibernate的执行效率;(当执行一次查询操作的时候,执行第二次查询操作,先检查缓存中是否有数据,如果有数据就不查询数据库…

大家好,又见面了,我是你们的朋友全栈君。

hibernate二级缓存(一)一级缓存与二级缓存

1.hibernate一级缓存

hibernate的一级缓存是session级别的缓存,一级缓存hibernate默认启用且不能被卸载,一个事务内有效。
特点:

  1. 使用一级缓存的目的是为了减少对数据库的访问次数,从而提升hibernate的执行效率;(当执行一次查询操作的时候,执行第二次查询操作,先检查缓存中是否有数据,如果有数据就不查询数据库,直接从缓存中获取数据);

  2. Hibernate中的一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数,只在session范围内有效,session关闭,一级缓存失败;

  3. 一级缓存的特点,只在session范围有效,作用时间短,效果不是特别明显,在短时间内多次操作数据库,效果比较明显。

  4. 当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,都会把对象放入session缓存中;

  5. session的缓存是由hibernate维护的,用户不能操作缓存内容;如果想操作缓存内容,必须通过hibernate提供的evict/clear方法操作

  6. 缓存相关的方法(在什么情况下使用上面方法呢?批量操作情况下使用,如Session.flush();先与数据库同步,Session.clear();再清空一级缓存内容):

      session.flush();让一级缓存与数据库同步;
      session.evict();清空一级缓存中指定的对象;
      session.clear();清空一级缓存中所有的对象;
    

综上: 一级缓存的生命周期和session的生命周期一致,当前session一旦关闭,一级缓存就消失了,因此一级缓存也叫session级的缓存或事务级缓存,一级缓存只存实体对象,它不会缓存一般的对象属性(查询缓存可以),即当获得对象后,就将该对象缓存起来,如果在同一session中再去获取这个对象时,它会先判断在缓存中有没有该对象的id,如果有则直接从缓存中获取此对象,反之才去数据库中取,取的同时再将此对象作为一级缓存处理。

2.二级缓存

Hibernate的二级缓存又称为”SessionFactory的缓存”,由于SessionFactory对象的生命周期和应用的整个过程对应,他是可选的,是一个可配置的插件,默认情况下SessionFactory不会启用这个插件。
由于二级缓存是被各session共享的,那么多个事务或者说线程同时访问修改二级缓存可能会会造成数据不一致问题。所以二级缓存只适合多读少写的场景。

那么什么样的数据适合放在二级缓存中呢?

  • 多读少写的数据
  • 不是很重要的数据
  • 常量数据

什么样的数据不适合放在二级缓存中呢?

  • 经常被修改的数据
  • 绝对不允许出现并发访问的数据。如财务数据,绝对不允许出现并发
  • 与其他应用共享的数据

3. 二级缓存的配置

这里只展示纯hibernate的二级缓存配置,如果要如spring结合,请参考spring sessionFactory配置里面的hibernate二级缓存参数。
下面的配置是基于hibernate5.3.7.Final版本

3.1 SessionFactory的配置

该版本的SessionFactory获取的最新方式如下:

public class SessionFactoryUtil {

    private SessionFactory sessionFactory;

    public SessionFactoryUtil() {
        setUp();
    }

    private void setUp() {
        // A SessionFactory is set up once for an application!
        final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
                .configure() // configures settings from hibernate.cfg.xml
                .build();
        try {
            sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
        } catch (Exception e) {
            e.printStackTrace();
            // The registry would be destroyed by the SessionFactory, but we had trouble building the SessionFactory
            // so destroy it manually.
            StandardServiceRegistryBuilder.destroy(registry);
        }
    }
    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

registry 会自动加载resources路径下的hibernate.cfg.xml配置文件。hibernate.cfg.xml配置如下:

<!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.url">jdbc:mysql://localhost:3306/test</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>
        <!-- 数据库连接池的大小 -->
        <property name="connection.pool_size">5</property>
        <!-- 每次从数据库中取出并放到JDBC的Statement中的记录条数。Fetch Size设的越大,读数据库的次数越少,速度越快,Fetch Size越小,读数据库的次数越多,速度越慢-->
        <property name="jdbc.fetch_size">50</property>
        <!--批量插入,删除和更新时每次操作的记录数。Batch Size越大,批量操作的向数据库发送Sql的次数越少,速度就越快,同样耗用内存就越大-->
        <property name="jdbc.batch_size">23</property>
        <!-- SQL 方言 -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>
        <!-- 在控制台输出sql语句 -->
        <property name="show_sql">true</property>
        <!-- 在启动时根据配置更新数据库 -->
        <property name="hbm2ddl.auto">update</property>

        <!-- 二级缓存配置 -->
        <property name="hibernate.cache.use_second_level_cache">true</property>
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.internal.EhcacheRegionFactory</property>
        <property name="hibernate.cache.use_minimal_puts">true</property>
        <property name="hibernate.cache.use_query_cache">true</property>
        <property name="hibernate.cache.region_prefix">customer-hibernate-cache</property>
        <property name="hibernate.cache.default_cache_concurrency_strategy">nonstrict-read-write</property>


        <mapping class="com.foo.model.Event"/><!-- 注册我们的实体映射类-->
    </session-factory>
</hibernate-configuration>

3.2 基本的代码示例

有了SessionFactory后通过session进行增删改查等操作

public class Main {

    public static void main(String[] args) {
        SessionFactoryUtil sessionFactoryUtil = new SessionFactoryUtil();
        SessionFactory sessionFactory = sessionFactoryUtil.getSessionFactory();
        //1.查询单个实体
        doExecute(sessionFactory, new HibernateExecuteCallBack() {
            @Override
            public void execute(Session session) {
                Event event = session.get(Event.class, 7L);
                System.out.println(event);
            }
        });
         //2.查询单个实体
        doExecute(sessionFactory, new HibernateExecuteCallBack() {
            @Override
            public void execute(Session session) {
                Event event = session.get(Event.class, 7L);
                System.out.println(event);
            }
        });
    }
	public static void doExecute(SessionFactory sessionFactory, HibernateExecuteCallBack executeCallBack) {
        Session session = sessionFactory.openSession();
        session.beginTransaction();

        executeCallBack.execute(session);

        session.getTransaction().commit();
        session.close();
    }

    interface HibernateExecuteCallBack {
        void execute(Session session);
    }

上面的代码中首先得到一个sessionFactory ,然后通过doExecute封装session的整个执行流程的模版代码,HibernateExecuteCallBack 回调接口将实际执行操作分离,整个过程类似jdbcTemplate。

package com.foo.model;

import org.hibernate.annotations.CacheConcurrencyStrategy;

import javax.persistence.*;
import java.util.Date;

/**
 * @author JasonLin
 * @version V1.0
 * @date 2019/3/11
 */
@Entity
@Table(name = "event")
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Event {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String title;

    @Column(name = "_date")
    private Date date;

    public Event(){

    }

    public Event(String title, Date date) {
        this.title = title;
        this.date = date;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Event{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", date=" + date +
                '}';
    }
}

Event的代码随意,是通过注解配置实体,但是必须注意在hibernate.cfg.xml里面必须配置:

<mapping class="com.foo.model.Event"/><!-- 注册我们的实体映射类-->

3.2 二级缓存的配置

在上面的配置里面其实已经加上了二级缓存

		<!--是否启用二级缓存-->
        <property name="hibernate.cache.use_second_level_cache">true</property>
        <!--缓存的具体实现-->
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.internal.EhcacheRegionFactory</property>
        <!--以频繁的读操作为代价, 优化二级缓存来最小化写操作-->
        <property name="hibernate.cache.use_minimal_puts">true</property>
        <!--是否使用查询缓存-->
        <property name="hibernate.cache.use_query_cache">true</property>
        <!--缓存的前缀-->
        <property name="hibernate.cache.region_prefix">customer-hibernate-cache</property>
        <!--缓存的策略-->
        <property name="hibernate.cache.default_cache_concurrency_strategy">nonstrict-read-write</property>

这里我们使用的是EhcacheRegionFactory来作为二级缓存的具体实现。当然也可以自己实现RegionFactory,比如通过redis来作为hibernate的二级缓存。

hibernate.cache.default_cache_concurrency_strategy指定hibernate二级缓存策略,hibernate共有五种缓存策略

public enum CacheConcurrencyStrategy {
	/**
	 * Indicates no concurrency strategy should be applied.
	 */
	NONE( null ),
	/**
	 * Indicates that read-only strategy should be applied.
	 *
	 * @see AccessType#READ_ONLY
	 */
	READ_ONLY( AccessType.READ_ONLY ),
	/**
	 * Indicates that the non-strict read-write strategy should be applied.
	 *
	 * @see AccessType#NONSTRICT_READ_WRITE
	 */
	NONSTRICT_READ_WRITE( AccessType.NONSTRICT_READ_WRITE ),
	/**
	 * Indicates that the read-write strategy should be applied.
	 *
	 * @see AccessType#READ_WRITE
	 */
	READ_WRITE( AccessType.READ_WRITE ),
	/**
	 * Indicates that the transaction strategy should be applied.
	 *
	 * @see AccessType#TRANSACTIONAL
	 */
	TRANSACTIONAL( AccessType.TRANSACTIONAL );
  • CacheConcurrencyStrategy.None 不使用缓存
  • CacheConcurrencyStrategy.READ_ONLY:只读模式,在此模式下,如果对数据进行更新操作,会抛出异常。
  • CacheConcurrencyStrategy.READ_WRITE:读写模式在更新缓存的时候会对缓存里的数据加锁,其他事物如果去取相应缓存中的数据,发现被锁了,直接去数据库中取。
  • CacheConcurrencyStrategy.NONSTRICT_READ_WRITE:不严格的读写模式则不会对缓存数据加锁
  • CacheConcurrencyStrategy.TRANSACTIONAL:事务模式指缓存支持事务,当事务回滚,缓存也回滚,只支持JTA环境

一切配置完毕,下面来看下具体的执行结果,

Hibernate: select event0_.id as id1_0_0_, event0_._date as _date2_0_0_, event0_.title as title3_0_0_ from event event0_ where event0_.id=?
Event{id=7, title='Our very first event!', date=2019-03-11 13:45:21.0}
Event{id=7, title='Our very first event!', date=2019-03-11 13:45:21.0}

由于我们的第一次操作是在不同的session里面,我们看到配置了缓存之后只发送了一条sql语句。代表缓存配置成功。在后面我们将具体讲解hibernate二级缓存的实现原理并自己用map实现一个简单的RegionFactory。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/142230.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 计算机发展概述教案_计算机的过去与未来 教案

    计算机发展概述教案_计算机的过去与未来 教案《计算机发展史教案》由会员分享,可在线阅读,更多相关《计算机发展史教案(3页珍藏版)》请在人人文库网上搜索。1、计算机发展与应用说课稿教材分析本课选自七年级信息技术上第三课,计算机的产生与发展。本课的内容较多,经过我的分析,我这节课的内容为:1,计算机的产生2,计算机的发展历史3,计算机的未来发展方向。本课知识为了解性知识,学生学完本课可以了解到今生今世的产生与发展历史,并且理解计算机的未来发展方…

    2022年10月18日
    0
  • 时滞微分方程求解_泛函微分方程内容设计

    时滞微分方程求解_泛函微分方程内容设计时滞微分方程(DDE)是当前时间的解与过去时间的解相关的常微分方程。该时滞可以固定不变、与时间相关、与状态相关或与导数相关。要开始积分,通常必须提供历史解,以便求解器可以获取初始积分点之前的时间的解。常时滞DDE具有常时滞的微分方程组的形式如下:y′(t)=f(t,y(t),y(t−τ1),…,y(t−τk)).y'(t)=f(t,y(t),y(t−τ_1),…,y(t−τ_k)).y′(t)=f(t,y(t),y(t−τ1​),…,y(t−τk​)).此处,t为自变量,y为因变量的列向量,

    2022年10月1日
    0
  • 阿里云Ubuntu部署java web(2) – 配置tomcat「建议收藏」

    阿里云Ubuntu部署java web(2) – 配置tomcat

    2022年1月27日
    34
  • java session有效期设置方式「建议收藏」

    java session有效期设置方式「建议收藏」session默认有效期是30分钟,设置session的有效期有三种方法:1.在tomcat中的server.xml中定义:在tomcat中的conf/server.xml文件可以修改服务器上的所有程序的默认有效期,设置单位为毫秒,定义代码如下:<Contextpath=”/test”docBase=”/test”  defaultSessionTimeOut=”360…

    2022年7月12日
    14
  • 【gTest】gtest简介及简单使用

    【gTest】gtest简介及简单使用【gTest】gtest简介及简单使用gtest是一个跨平台(Liunx、MacOSX、Windows、Cygwin、WindowsCEandSymbian)的C++测试框架,有google公司发布。gtest测试框架是在不同平台上为编写C++测试而生成的。从http://code.google.com/p/googletest/downloads/detail?name=gtest-1.7.0.zip&can=2&q=下载最新的gtest-1.7.0版本在Windows下编

    2022年9月29日
    0
  • django csdn_怎么使用cookie登录

    django csdn_怎么使用cookie登录前言cookie:在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录

    2022年7月30日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号