Hibernate Caching - Bài 2: Second Level Cache
Chào các bạn! Chúng ta lại quay trở lại trong series hướng dẫn về Hibernate Caching. Trước khi đọc những gì mình viết dưới đây, hãy dành chút thời gian để nhớ lại những gì mình đã đề cập đến trong bài Hibernate Caching - Bài 1: Second Level Cache nhé. Link source code sample tại đây: ...
Chào các bạn! Chúng ta lại quay trở lại trong series hướng dẫn về Hibernate Caching. Trước khi đọc những gì mình viết dưới đây, hãy dành chút thời gian để nhớ lại những gì mình đã đề cập đến trong bài Hibernate Caching - Bài 1: Second Level Cache nhé.
- Link source code sample tại đây: https://github.com/nhs3108/hibernate , có bao gồm file dump DB đấy các bạn nhé
2. Second Level Cache (L2)
2.1. Giới thiệu
Như mình đã đề cập trong bài trước, phạm vi ảnh hưởng của First Level Cache(L1) là nội session. Nghĩa là khi bạn gọi đối tượng X trong sessionA, thì nó sẽ chỉ tìm đối tượng X trong sessionA và trong trường hợp sessionA không có, nó sẽ thực thi câu lệnh truy vấn tới DB.
Khác với L1, phạm vi lưu trữ đối tượng được mở rộng hơn trong L2, sang mức SessionFactory thay vì session như L1. Bạn có thể hình dung rằng, thay vì các session có một vùng nhớ cache riêng lẻ (ở L1), thì tất cả chúng (những session được tạo ra bởi cùng 1 session factory) sẽ có chung một "ngôi nhà" to đùng và các đối tượng được cache lại sẽ nằm ở đó và khi gọi cũng từ đó mà được lấy ra. Các đối tượng này khi được cache lại "ngôi nhà" này cũng sẽ có những phòng mà 1, 1 vài hoặc 1 nhóm sẽ dùng chung mà khái niệm trong L2 gọi là region (bạn có thể hiểu như đó là tên phòng nơi chúng được lưu trữ) và mặc định nó là Full Class Name của đối tượng đó (ví dụ com.nhs3108.hibernate.User). Khái niệm này khá quá trọng mà bạn sẽ cần phải nhớ để hiểu ở phần sau.
LƯU Ý:: L2 sẽ chỉ hoạt động trong những trường hợp sau:
- Khi bạn lấy đối tượng bằng ID (tuy nhiên, nếu bạn sử dụng SQL/HQL thì cũng không được cho dù bạn có dùng lệnh where id=?)
- Khi các liên kết ngoại của bạn là lazy-loaded (hoặc eager-loaded với selects thay vì joins)
2.2: Enable Second Level Cache
Để bật Second Level Cache trong Hibernate, bạn chỉ cần cấu hình 2 thuộc tính
- hibernate.cache.use_second_level_cache : để báo với Hibernate rằng chúng ta có(true) dùng L2 hay không(false)
- hibernate.cache.region.factory_class: để chỉ định tên lớp Region Factory
như sau
<properties> ... <property name="hibernate.cache.use_second_level_cache" value="true"/> <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/> ... </properties>
2.3: Cache Concurrency Strategy (CCS)
(Mình dịch nôm na nó như là Cơ chế/Chiến lược truy cập đồng thời) Dựa vào từng use-case, ta có thể tùy ý chọn các kiểu CCS sao cho phù hợp
- READ_ONLY: Chỉ được sử dụng cho các thực thể được đọc thường xuyên nhưng không bao giờ bị thay đổi. Mình hay gọi đó là master-data. Ví dụ trong DB của bạn có 1 bảng Category(category_id, category_name) và trong list các chức năng của bạn không có cái nào làm thay đổi dữ liệu của bất cứ record nào trong bảng category cả. Đó là 1 ví dụ nho nhỏ thôi, còn đâu là tùy thuộc vào dữ liệu trong hệ thống mà ta sử dụng nữa.
- NONSTRICT_READ_WRITE: Cơ chế này không đảm bảo tính nhất quán giữa bộ nhớ cache và cơ sở dữ liệu. Sử dụng chiến lược này nếu dữ liệu hầu như không thay đổi và trong trường hợp rất hiếm còn lại, thì sự không nhất quán đó cũng không phải là vấn đề.
- READ_WRITE: Cơ chế này đảm bảo tính nhất quán dữ liệu cao bằng việc sử dụng 'soft lock`. Khi một thực thể đã được cache bị update, một 'soft lock' được lưu lại trong cache cho entity và nó sẽ được giải phóng (release) khi transaction được commit. Tất cả các transaction nếu truy cập vào các đối tượng đang bị softblock sẽ được lấy trực tiếp từ cơ sở dữ liệu. Bạn hình dung là, nếu 1 TRANSACTION A đang muốn update đối tượng X, thì nó sẽ "khóa" đối tượng X lại và khi các TRANSACTION B, C muốn sử dụng đối tượng X, nó sẽ phải lấy trực tiếp từ DB thay vì từ cache cho đến khi nào TRANSACTION A mở khóa cho đối tượng X (như mình vừa nói là sau khi transaction commit)
- TRANSACTIONAL: Cơ chế này đảm bảo các transaction làm việc biệt lập hoàn toàn. Cái này chắc fai nhờ các bạn tìm hiểu thêm. Mấy thằng CacheProvider mình liệt kê ngay dứoi đây cũng ko hỗ trợ nó