Hibernate(14)什么是Hibernate的二级缓存?

Hibernate的二级缓存(Second-Level Cache)是超出Session范围的缓存,可以在多个Session之间共享。二级缓存用来存储那些在不同事务之间共享的数据,减少对数据库的访问,提高应用程序的性能。与一级缓存不同,二级缓存是可选的,需要显式配置和启用。

主要特点

  1. Session工厂范围内共享:二级缓存可以在多个Session之间共享数据。
  2. 可配置:需要显式配置缓存提供者和缓存策略。
  3. 缓存实体和集合:可以缓存实体、集合和查询结果。
  4. 持久性缓存:常用于缓存那些不经常修改的数据。

主要组件

  1. 缓存提供者:例如 Ehcache、Infinispan、Hazelcast 等。
  2. 缓存策略:配置缓存的使用策略,例如读写、只读等。

示例项目结构

为了深入理解二级缓存,下面是一个完整的示例,包括如何配置Hibernate文件、定义实体类、以及演示二级缓存的行为。

配置文件 hibernate.cfg.xml

假设使用Ehcache作为二级缓存提供者。

xml 复制代码
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- 数据库连接配置 -->
        <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/your_database</property>
        <property name="hibernate.connection.username">your_username</property>
        <property name="hibernate.connection.password">your_password</property>

        <!-- Hibernate 属性配置 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
        <property name="hibernate.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.EhCacheRegionFactory</property>
        <property name="hibernate.cache.use_query_cache">true</property>

        <!-- 映射类配置 -->
        <mapping class="com.example.domain.Student"/>
    </session-factory>
</hibernate-configuration>

Ehcache 配置文件 ehcache.xml

xml 复制代码
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd"
         updateCheck="false">
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="300"
            timeToLiveSeconds="600"
            overflowToDisk="false"
            memoryStoreEvictionPolicy="LRU"/>
    <cache name="com.example.domain.Student"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="300"
           timeToLiveSeconds="600"
           overflowToDisk="false"
           memoryStoreEvictionPolicy="LRU"/>
</ehcache>

HibernateUtil 类

java 复制代码
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
    private static final SessionFactory sessionFactory;

    static {
        try {
            // 从配置文件创建SessionFactory
            sessionFactory = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
        } catch (Throwable ex) {
            // 记录启动失败的错误
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

实体类 Student

java 复制代码
package com.example.domain;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    private int age;

    public Student() {}

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getters 和 setters
    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

二级缓存示例代码

下面的示例展示了二级缓存的基本行为,包括如何在多个Session中共享缓存数据。

java 复制代码
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

public class HibernateSecondLevelCacheExample {
    public static void main(String[] args) {
        // 获取SessionFactory
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        Session session = null;
        Transaction transaction = null;

        // 向数据库添加一个测试对象
        try {
            session = sessionFactory.openSession();
            transaction = session.beginTransaction();

            Student student = new Student("John Doe", 20);
            session.save(student);

            transaction.commit();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.close();
            }
        }

        // 第一次查询,发出SQL语句,并将数据放入二级缓存
        try {
            session = sessionFactory.openSession();
            transaction = session.beginTransaction();

            Student student = session.get(Student.class, 1L);
            System.out.println("First Query: " + student.getName() + ", Age: " + student.getAge());

            transaction.commit();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.close();
            }
        }

        // 第二次查询,从二级缓存中读取数据,不发出SQL语句
        try {
            session = sessionFactory.openSession();
            transaction = session.beginTransaction();

            Student student = session.get(Student.class, 1L);
            System.out.println("Second Query: " + student.getName() + ", Age: " + student.getAge());

            transaction.commit();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.close();
            }
        }

        // 关闭SessionFactory
        sessionFactory.close();
    }
}

详细解释

  1. 配置二级缓存 :在hibernate.cfg.xml中启用二级缓存,指定缓存提供者和缓存策略。

    xml 复制代码
    <property name="hibernate.cache.use_second_level_cache">true</property>
    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
    <property name="hibernate.cache.use_query_cache">true</property>
  2. 配置Ehcache :在ehcache.xml中配置缓存区域及其属性。

    xml 复制代码
    <cache name="com.example.domain.Student"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="300"
           timeToLiveSeconds="600"
           overflowToDisk="false"
           memoryStoreEvictionPolicy="LRU"/>
  3. 注解实体类 :使用@Cache注解和@CacheConcurrencyStrategy指定缓存策略。

    java 复制代码
    @Entity
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    public class Student {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
        private int age;
    }
  4. 第一次查询:在一个新的Session中查询实体,将数据放入二级缓存。

    java 复制代码
    Student student = session.get(Student.class, 1L);
  5. 第二次查询:在另一个新的Session中查询相同的实体,从二级缓存中读取数据,不发出SQL语句。

    java 复制代码
    Student student = session.get(Student.class, 1L);

事务管理

在进行数据库操作时,需要开启事务,并在操作完成后提交事务。如果操作失败,则回滚事务以确保数据一致性。

java 复制代码
Transaction transaction = session.beginTransaction();
try {
    // 持久化操作
    transaction.commit();
} catch (Exception e) {
    if (transaction != null) {
        transaction.rollback();
    }
    e.printStackTrace();
}

总结

Hibernate的二级缓存是超出Session范围的缓存,可以在多个Session之间共享数据。它通过减少数据库的访问次数,提高了应用程序的性能。

相关推荐
llz_1121 小时前
web-第二次课后作业
前端·后端·web
红尘散仙7 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记8 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
会编程的土豆9 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
喵个咪9 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
basketball6169 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
qq_2518364579 小时前
SpringBoot+Vue 共享电池柜管理系统 完整实现 前后端分离项目实战 完整代码
vue.js·spring boot·后端
zhangxingchao10 小时前
AI 大模型核心六:量化、Workflow 与 Agent、多轮 RAG
前端·人工智能·后端
IT_陈寒11 小时前
Vite打包时遇到的坑,原来问题出在这里
前端·人工智能·后端
ayqy贾杰12 小时前
基层管理的三板斧,在AI时代行不通了
前端·后端·团队管理