Bài 4: Caching trong Hibernate

·

5 min read

1. Giới thiệu về cơ chế caching

Tại sao cần caching? Caching giúp cải thiện hiệu suất của ứng dụng bằng cách lưu trữ tạm thời các kết quả truy vấn và các đối tượng thường xuyên được truy cập. Điều này giảm thiểu số lần truy vấn tới cơ sở dữ liệu, từ đó giảm tải cho hệ thống và tăng tốc độ xử lý.

Các mức độ caching trong Hibernate Hibernate hỗ trợ hai mức độ caching chính:

  • First Level Cache: Cache cấp 1, mặc định được bật và gắn liền với session. Mỗi session có một cache cấp 1 riêng.

  • Second Level Cache: Cache cấp 2, có thể được bật hoặc tắt và có thể được chia sẻ giữa các session khác nhau.

2. First Level Cache

First Level Cache là gì? First Level Cache là cache mặc định của Hibernate, được gắn liền với mỗi session. Khi một đối tượng được truy vấn lần đầu tiên trong một session, Hibernate sẽ lưu đối tượng đó vào cache. Các truy vấn tiếp theo tới cùng đối tượng trong cùng session sẽ được lấy từ cache thay vì truy vấn lại cơ sở dữ liệu.

Cách hoạt động của First Level Cache Khi bạn thực hiện một truy vấn, Hibernate sẽ kiểm tra cache cấp 1 trước. Nếu đối tượng đã có trong cache, nó sẽ được lấy từ cache. Nếu không, Hibernate sẽ truy vấn cơ sở dữ liệu và lưu kết quả vào cache.

Ví dụ cụ thể

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();

// Truy vấn lần đầu tiên, Hibernate sẽ truy vấn cơ sở dữ liệu
User user1 = session.get(User.class, 1L);
System.out.println(user1.getUsername());

// Truy vấn lần thứ hai, Hibernate sẽ lấy đối tượng từ cache
User user2 = session.get(User.class, 1L);
System.out.println(user2.getUsername());

transaction.commit();
session.close();

Trong ví dụ này, đối tượng User với ID 1 được truy vấn lần đầu tiên sẽ được lấy từ cơ sở dữ liệu và lưu vào cache. Truy vấn lần thứ hai sẽ lấy đối tượng từ cache.

3. Second Level Cache

Second Level Cache là gì? Second Level Cache là cache cấp 2, có thể được chia sẻ giữa các session khác nhau. Để sử dụng Second Level Cache, bạn cần cấu hình và bật nó trong file cấu hình Hibernate.

Cách cấu hình và sử dụng Second Level Cache

  • Bước 1: Thêm dependency cho thư viện cache (ví dụ: EHCache) vào pom.xml hoặc build.gradle.
<!-- Maven -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
    <version>5.4.32.Final</version>
</dependency>
// Gradle
implementation 'org.hibernate:hibernate-ehcache:5.4.32.Final'
  • Bước 2: Cấu hình Second Level Cache trong file hibernate.cfg.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.provider_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
  • Bước 3: Đánh dấu entity sử dụng cache với annotation @Cacheable@Cache.
@Entity
@Table(name = "users")
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

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

    // Getters and setters
}

Ví dụ cụ thể về sử dụng Second Level Cache

Session session1 = HibernateUtil.getSessionFactory().openSession();
Transaction transaction1 = session1.beginTransaction();

// Truy vấn lần đầu tiên, Hibernate sẽ truy vấn cơ sở dữ liệu và lưu vào cache cấp 2
User user1 = session1.get(User.class, 1L);
System.out.println(user1.getUsername());

transaction1.commit();
session1.close();

Session session2 = HibernateUtil.getSessionFactory().openSession();
Transaction transaction2 = session2.beginTransaction();

// Truy vấn lần thứ hai, Hibernate sẽ lấy đối tượng từ cache cấp 2
User user2 = session2.get(User.class, 1L);
System.out.println(user2.getUsername());

transaction2.commit();
session2.close();

Trong ví dụ này, đối tượng User với ID 1 được truy vấn lần đầu tiên sẽ được lưu vào cache cấp 2. Truy vấn lần thứ hai từ session khác sẽ lấy đối tượng từ cache cấp 2.

4. Query Cache

Query Cache là gì? Query Cache là một cơ chế cache bổ sung để lưu trữ các kết quả của các truy vấn HQL. Nó hữu ích khi bạn cần cache các kết quả truy vấn phức tạp.

Cấu hình và sử dụng Query Cache

  • Bước 1: Bật Query Cache trong file hibernate.cfg.xml.
<property name="hibernate.cache.use_query_cache">true</property>
  • Bước 2: Sử dụng Query Cache trong các truy vấn HQL.
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();

Query query = session.createQuery("FROM User WHERE username = :username");
query.setParameter("username", "johndoe");
query.setCacheable(true);

List<User> results = query.list();

transaction.commit();
session.close();

Trong ví dụ này, kết quả của truy vấn sẽ được lưu vào Query Cache và có thể được tái sử dụng cho các truy vấn tương tự trong tương lai.

5. Ví dụ cụ thể về sử dụng caching trong Hibernate

Cấu hình caching trong hibernate.cfg.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>
        <!-- Các cấu hình khác -->

        <!-- Bật Second Level Cache -->
        <property name="hibernate.cache.use_second_level_cache">true</property>
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

        <!-- Bật Query Cache -->
        <property name="hibernate.cache.use_query_cache">true</property>
    </session-factory>
</hibernate-configuration>

Sử dụng caching với các entity và query

@Entity
@Table(name = "products")
@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
}

// Lưu đối tượng Product vào cache
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();

Product product = new Product();
product.setName("Laptop");
product.setPrice(1000.0);
session.save(product);

transaction.commit();
session.close();

// Truy vấn đối tượng Product từ cache
Session session2 = HibernateUtil.getSessionFactory().openSession();
Transaction transaction2 = session2.beginTransaction();

Product product2 = session2.get(Product.class, product.getId());
System.out.println(product2.getName());

transaction2.commit();
session2.close();

// Sử dụng Query Cache
Session session3 = HibernateUtil.getSessionFactory().openSession();
Transaction transaction3 = session3.beginTransaction();

Query query = session3.createQuery("FROM Product WHERE price > :price");
query.setParameter("price", 500.0);
query.setCacheable(true);

List<Product> products = query.list();

transaction3.commit();
session3.close();

Trong ví dụ này, chúng ta sử dụng cache cấp 2 để lưu trữ và truy vấn đối tượng Product. Chúng ta cũng sử dụng Query Cache để lưu trữ kết quả của truy vấn tìm kiếm các sản phẩm có giá lớn hơn 500.

Qua bài hướng dẫn này, bạn đã nắm được cách sử dụng các cơ chế caching trong Hibernate, bao gồm First Level Cache, Second Level Cache, và Query Cache. Những kiến thức này sẽ giúp bạn tối ưu hóa hiệu suất ứng dụng và quản lý tài nguyên hiệu quả hơn trong các ứng dụng Java sử dụng Hibernate.