Bài viết gốc bạn có thể xem ở đây.

Giới thiệu

Trong bài đăng lần trước tôi đã giới thiệu quá trình chuyển đổi trạng thái (entity state transitions)  trong mô hình ORM.

Tất cả các quá trình chuyển đổi trạng thái được quản lý (entity state transitions) đã phiên dịch sang các câu lệnh của database khi Persistence Context hiện tại đã được flush.
(Lời người dịch: bình thường các entity sẽ có trạng thái khác nhau và chỉ khi ở trạng thái Persistent thì chúng mới lắng nghe những thay đổi và đồng bộ xuống database). Nhưng flush trong Hibernate thì không phải lúc nào cũng rõ ràng như chúng ta nghĩ.

Write-behind

Hibernate luôn cố gắng hoãn lại giai đoạn Persistence xả (flushing) cho đến thời điểm cuối cùng có thể. Phương pháp này thường được biết đến với tên gọi là transactional write-behind.

Write-behind có liên quan đến Hibernate flush hơn bất kì transaction (cuộc giao dịch) lô gíc hay vật lý nào. Trong một transaction, flush có thể xảy ra rất nhiều lần.

Các thay đổi của flush chỉ hiển thị (visible) cho các transaction dữ liệu hiện tại. Cho đến khi transaction hiện tại được commit, các transaction đồng thời khác (other concurrent transactions) không thể được hiển thị. 

Trong persistence context, còn được biết tới là bộ nhớ đệm cấp 1 (first level cache), hoạt động như một trung gian giữa trạng thái entity hiện tại và database.

Trong lý thuyết về bộ nhớ đệm (caching theory), quá trình đồng bộ hoá write-behind yêu cầu tất cả phải được xảy ra dựa vào bộ nhớ đệm, nó cũng là nơi chịu trách nhiệm cho việc đồng bộ hoá cho đến khi dữ liệu thực sự được lưu xuống cơ sở dữ liệu.

Giảm vấn đề về tranh chấp lock

Mỗi khi câu lệnh DML (DML statement) chạy bên trong một transaction cơ sở dữ liệu. Dựa vào mức độ bảo mật hiện tại của transaction database (transaction isolation level), khoá (chia sẻ hoặc công khai) để có thể yêu cầu lấy hoặc thay đổi các hàng trong bảng.

Giảm thời gian kiểm soát khoá sẽ làm giảm xác suất khoá chết (dead-lock) và theo lý thuyết mở rộng (scalability theory), điều này sẽ làm tăng băng thông. Các khoá luôn được xuất hiện ở các lần thực thi nối tiếp nhau, và theo quy tắc của Amdahl , tốc độ tối đa tỷ lệ nghịch với các phần nối tiếp nhau của chương trình đang thực thi (lời người dịch: có nghĩa là nếu càng nhiều quá trình xử lý xảy ra thì tối độ sẽ giảm đi).

Ngay cả ở mức độ bảo mật READ_COMMITTED, câu lệnh UPDATEDELETE có được các khoá để tránh cho các transaction xảy đồng thời ở các hàng mà đang được chỉnh sửa.
(lời người dịch: các transaction sẽ phải chờ đợi đến khi nào tất cả các thay đổi chắc chắn thành công thì transaction sau mới có thể được thực thi.)

Vì vậy, việc trì hoãn các câu lệnh khoá (UPDATE/DELETE) có thể làm tăng hiệu suất nhưng chúng ta phải đảm bảo rằng tính nhất quán của dữ liệu không bị ảnh hưởng.
 

Batching (Hàng loạt)

Việc hoãn đồng bộ hoá trạng thái entity có một ưu điểm khác. Vì tất cả các thay đổi được thực hiện cùng một lúc, nên Hibernate có thể hưởng lợi từ việc tối ưu hoá hàng loạt của JDBC (JDBC batching optimization).

Batching cải thiện hiệu suất bằng cách nhóm nhiều câu lệnh DML vào một lần xử lý duy nhất, do đó giảm các sự di chuyển xung quanh database (database round-trips).

(lời người dịch: mọi người có thể tìm hiểu thêm về database round-trips ở đây.)


Tính nhất quán của Read-your-own-writes

Vì các câu lệnh truy vấn luôn chạy dựa vào database (trừ khi bộ nhớ đệm thứ hai được truy cập), chúng ta cần luôn chắc chắn rằng tất cả sẽ được đồng bộ trước khi câu truy vấn bắt đầu chạy.

Do đó, cả JPA và Hibernate đều có một phương pháp đồng bộ là flush-before-query.

Từ cách flush của JPA đến Hibernate

JPA FLUSHMODETYPE

HIBERNATE FLUSHMODE

CHI TIẾT VỀ CÁCH TRIỂN KHAI CỦA HIBERNATE

AUTO

AUTO

Session sẽ thỉnh thoảng flush trước khi câu truy vấn được thực thi.

COMMIT

COMMIT

Session chỉ được flush khi mà một transaction đã commit.

 

ALWAYS

Session luôn luôn flush trước khi câu truy vấn được thực thi.

 

MANUAL

Session chỉ có thể flush một cách thủ công. (manually flushed)

 

NEVER

Không được chấp nhận. Sử dụng MANUAL thay thế cho cái này. Ban đầu cái tên này được đặt cho chế độ flush thủ công nhưng nó khiến người dùng hiểu rằng session không bao giờ được flush.

 

Phạm vi của Current Flush

Persistence Context được định nghĩa ở chế độ flush mặc định, điều này có thể được ghi đè khi Hibernate Session được tạo ra. Các câu truy vấn có thể dùng một phương pháp flush bất kỳ nhưng cũng có thể từ chối sử dụng chế độ flush của Persistence Context hiện tại.
 

Phạm vi

HIBERNATE

JPA

Persistence Context

Session

EntityManager

Câu truy vấn

Query

Criteria

Query

TypedQuery

 

Chú thích của người dịch:
Tìm hiểu thêm về bộ nhớ đệm cấp 1 (first level cache) ở đây.