Hibernate(51)Hibernate的查询缓存如何使用?

Hibernate的查询缓存(Query Cache)可以显著提高重复查询的性能。查询缓存存储的是查询结果的集合,而不是单个实体。要使用查询缓存,需要启用Hibernate的二级缓存,并对特定的查询启用缓存。以下是详细的使用步骤和代码示例。

1. 添加依赖

首先,确保在项目中添加了Hibernate和缓存提供者的依赖。以下是使用Ehcache作为缓存提供者的Maven依赖配置:

xml 复制代码
<dependencies>
    <!-- Hibernate Core -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.6.3.Final</version>
    </dependency>
    <!-- Ehcache -->
    <dependency>
        <groupId>org.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>3.9.0</version>
    </dependency>
    <!-- Hibernate Ehcache Integration -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-ehcache</artifactId>
        <version>5.6.3.Final</version>
    </dependency>
</dependencies>

2. 配置Hibernate

在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.cache.use_second_level_cache">true</property>
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.jcache.JCacheRegionFactory</property>
        <property name="hibernate.javax.cache.provider">org.ehcache.jsr107.EhcacheCachingProvider</property>
        <property name="hibernate.cache.use_query_cache">true</property>

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

3. 配置Ehcache

创建Ehcache的配置文件 ehcache.xml,并将其放置在类路径的根目录下。

xml 复制代码
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns='http://www.ehcache.org/v3'
        xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd">

    <cache alias="com.example.domain.Product">
        <key-type>java.lang.Long</key-type>
        <value-type>com.example.domain.Product</value-type>
        <expiry>
            <ttl unit="seconds">600</ttl>
        </expiry>
        <resources>
            <heap unit="entries">1000</heap>
            <offheap unit="MB">100</offheap>
        </resources>
    </cache>

    <cache alias="org.hibernate.cache.internal.StandardQueryCache">
        <key-type>java.lang.String</key-type>
        <value-type>java.lang.Object</value-type>
        <expiry>
            <ttl unit="seconds">600</ttl>
        </expiry>
        <resources>
            <heap unit="entries">1000</heap>
            <offheap unit="MB">100</offheap>
        </resources>
    </cache>

    <cache alias="org.hibernate.cache.spi.UpdateTimestampsCache">
        <key-type>java.lang.String</key-type>
        <value-type>java.lang.Long</value-type>
        <expiry>
            <ttl unit="seconds">600</ttl>
        </expiry>
        <resources>
            <heap unit="entries">1000</heap>
            <offheap unit="MB">100</offheap>
        </resources>
    </cache>
</config>

4. 配置实体类

在需要缓存的实体类上添加缓存注解。

java 复制代码
import javax.persistence.*;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity
@Table(name = "product")
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "price")
    private Double price;

    // Getters and Setters
}

5. 使用查询缓存

以下代码展示了如何使用Hibernate的查询缓存。

java 复制代码
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import java.util.List;

public class HibernateQueryCacheExample {
    private static final SessionFactory sessionFactory;

    static {
        try {
            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 void main(String[] args) {
        // 插入一些产品
        insertProduct("Laptop", 1000.0);
        insertProduct("Phone", 500.0);

        // 第一次查询(会从数据库中加载)
        List<Product> products1 = getProducts();
        products1.forEach(product -> System.out.println("First query: " + product.getName()));

        // 第二次查询(会从缓存中加载)
        List<Product> products2 = getProducts();
        products2.forEach(product -> System.out.println("Second query: " + product.getName()));

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

    private static void insertProduct(String name, Double price) {
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        try {
            Product product = new Product();
            product.setName(name);
            product.setPrice(price);
            session.save(product);
            transaction.commit();
            System.out.println("Product " + name + " inserted");
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    @SuppressWarnings("unchecked")
    private static List<Product> getProducts() {
        Session session = sessionFactory.openSession();
        try {
            Query<Product> query = session.createQuery("from Product");
            query.setCacheable(true); // 启用查询缓存
            return query.list();
        } finally {
            session.close();
        }
    }
}

解释

  1. 配置Hibernate :在hibernate.cfg.xml中启用了二级缓存和查询缓存,并指定了Ehcache作为缓存提供者。
  2. 配置Ehcache :在ehcache.xml中为实体类和查询缓存分别配置了缓存策略。
  3. 配置实体类 :在需要缓存的实体类Product上添加了@Cacheable@Cache注解。
  4. 使用查询缓存
    • getProducts方法中,通过调用query.setCacheable(true)启用查询缓存。
    • 第一查询会从数据库中加载数据,并将结果缓存。
    • 第二次查询相同的数据时,会从缓存中加载,从而提高性能。

使用查询缓存的注意事项

  1. 查询结果的有效性 :查询缓存存储的是查询结果列表,因此,如果底层数据发生变化,查询缓存可能会变得无效。Hibernate会使用一个名为UpdateTimestampsCache的缓存区域来跟踪表的更新时间,从而维护查询缓存的一致性。
  2. 缓存策略:选择合适的缓存策略(如TTL、最大缓存条目数等)来平衡缓存的命中率和内存消耗。
  3. 缓存区域:可以为不同的查询定义不同的缓存区域,以便更细粒度地控制缓存行为。

通过合理配置和使用查询缓存,可以显著提高Hibernate应用程序的查询性能。希望这些详细的解释和代码示例能帮助您更好地理解和应用Hibernate的查询缓存。

相关推荐
BUG研究员_25 分钟前
LangGraph节点缓存-CachePolicy
python·缓存·langraph
Rain的Java大神之路1 小时前
手写一个Spring容器
java·后端·mysql·spring·面试
Wang's Blog1 小时前
Java框架快速入门: Spring Security+OAuth2之定制登录页
java·开发语言·spring
霸道流氓气质1 小时前
Spring AI vs Spring AI Alibaba:技术选型与平滑迁移策略
java·人工智能·spring
tryxr1 小时前
Redis 的背景知识
数据库·redis·缓存
莫得感情 o2 小时前
Redis 08 · 主从复制:全量同步、增量同步与复制延迟
redis·缓存
m0_5873830013 小时前
全民健身解决方案软件开发实战:从架构设计到落地指南
java·spring boot·spring·架构·需求分析
wno70414 小时前
Spring Cloud Hystrix服务容错
spring·spring cloud·hystrix
刃神太酷啦14 小时前
Redis 进阶核心:持久化 (RDB/AOF)、事务与主从复制全解析----《Hello Redis!》(5)
linux·c语言·数据库·c++·redis·缓存·bootstrap
用户274621291728016 小时前
深入 Spring AI ChatClient:从一行代码到 LLM 调用的完整旅程
spring