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的查询缓存。

相关推荐
魔芋红茶4 小时前
Spring Security 学习笔记 4:用户/密码认证
笔记·学习·spring
我爱娃哈哈4 小时前
SpringBoot + Spring Security + RBAC:企业级权限模型设计与动态菜单渲染实战
spring boot·后端·spring
虹科网络安全4 小时前
艾体宝新闻 | Redis 月度更新速览:2025 年 12 月
数据库·redis·缓存
雪碧聊技术4 小时前
4.Spring整合LangChain4j
spring·langchain4j·调用大模型
想用offer打牌6 小时前
Spring AI vs Spring AI Alibaba
java·人工智能·后端·spring·系统架构
码农幻想梦7 小时前
实验五 spring入门及IOC实验
java·后端·spring
七七七七079 小时前
【Redis】Ubuntu22.04安装redis++
数据库·redis·缓存
J_liaty9 小时前
Spring Security整合JWT与Redis实现权限认证
java·redis·spring·spring-security
什么都不会的Tristan9 小时前
redis-原理篇-Dict
数据库·redis·缓存