Trước tiên, tôi sẽ phân biệt giữa khóa lạc quan và bi quan, bởi vì chúng khác nhau về cơ chế cơ bản.
Khóa lạc quan được kiểm soát hoàn toàn bởi JPA và chỉ yêu cầu cột phiên bản bổ sung trong bảng DB. Nó hoàn toàn độc lập với công cụ DB cơ bản được sử dụng để lưu trữ dữ liệu quan hệ.
Mặt khác, khóa bi quan sử dụng cơ chế khóa được cung cấp bởi cơ sở dữ liệu bên dưới để khóa các bản ghi hiện có trong bảng. JPA cần biết cách kích hoạt các khóa này và một số cơ sở dữ liệu không hỗ trợ chúng hoặc chỉ một phần.
Bây giờ đến danh sách các loại khóa:
-
LockModeType.Optimistic
- Nếu các thực thể chỉ định trường phiên bản, thì đây là trường mặc định. Đối với các thực thể không có cột phiên bản, việc sử dụng loại khóa này không được đảm bảo hoạt động trên bất kỳ triển khai JPA nào. Chế độ này thường bị bỏ qua như được nêu bởi ObjectDB. Theo ý kiến của tôi, nó chỉ tồn tại để bạn có thể tính toán chế độ khóa động và vượt qua nó ngay cả khi cuối cùng khóa sẽ TỐI ƯU. Mặc dù vậy, khả năng sử dụng không thực sự xảy ra, nhưng thiết kế API luôn là một thiết kế tốt để cung cấp tùy chọn tham chiếu ngay cả giá trị mặc định.
-
Ví dụ:
`LockModeType lockMode = resolveLockMode(); A a = em.find(A.class, 1, lockMode);`
-
LockModeType.OPTIMISTIC_FORCE_INCREMENT
- Đây là một tùy chọn hiếm khi được sử dụng. Nhưng nó có thể hợp lý, nếu bạn muốn khóa tham chiếu đến thực thể này bởi một thực thể khác. Nói cách khác, bạn muốn khóa hoạt động với một thực thể ngay cả khi nó không được sửa đổi, nhưng các thực thể khác có thể được sửa đổi liên quan đến thực thể này.
- Ví dụ:Chúng tôi có Thực thể Sách và Giá. Có thể thêm Sách vào Giá, nhưng sách không có bất kỳ tham chiếu nào đến giá của nó. Việc khóa hành động chuyển sách sang giá là hợp lý để sách không bị xếp vào kệ khác (do một giao dịch khác) trước khi kết thúc giao dịch này. Để khóa hành động này, không đủ để khóa thực thể giá sách hiện tại, vì sách chưa phải ở trên giá. Việc khóa tất cả các giá sách mục tiêu cũng không có ý nghĩa gì, vì chúng có thể khác nhau trong các giao dịch khác nhau. Điều duy nhất có ý nghĩa là tự khóa thực thể sách, ngay cả khi trong trường hợp của chúng tôi, nó không bị thay đổi (nó không có tham chiếu đến giá sách của nó).
-
LockModeType.PESSIMISTIC_READ
- chế độ này tương tự như
LockModeType.PESSIMISTIC_WRITE
, nhưng khác ở một điều:cho đến khi khóa ghi được thực hiện trên cùng một thực thể bởi một giao dịch nào đó, nó sẽ không chặn việc đọc thực thể. Nó cũng cho phép các giao dịch khác khóa bằngLockModeType.PESSIMISTIC_READ
. Sự khác biệt giữa khóa WRITE và READ được giải thích rõ ràng ở đây (ObjectDB) và ở đây (OpenJPA). Nếu một thực thể đã bị khóa bởi một giao dịch khác, bất kỳ nỗ lực nào để khóa nó sẽ tạo ra một ngoại lệ. Hành vi này có thể được sửa đổi thành chờ một thời gian để khóa được giải phóng trước khi đưa ra một ngoại lệ và khôi phục giao dịch. Để làm điều đó, hãy chỉ địnhjavax.persistence.lock.timeout
gợi ý với số mili giây để đợi trước khi ném ngoại lệ. Có nhiều cách để thực hiện việc này ở nhiều cấp độ, như được mô tả trong hướng dẫn Java EE.
-
LockModeType.PESSIMISTIC_WRITE
- đây là phiên bản mạnh hơn của
LockModeType.PESSIMISTIC_READ
. KhiWRITE
đã có khóa, JPA với sự trợ giúp của cơ sở dữ liệu sẽ ngăn bất kỳ giao dịch nào khác đọc thực thể, không chỉ để ghi như vớiREAD
khóa. - Cách thức thực hiện điều này trong một nhà cung cấp JPA hợp tác với DB cơ bản không được quy định. Trong trường hợp của bạn với Oracle, tôi sẽ nói rằng Oracle không cung cấp một cái gì đó gần với
READ
Khóa.SELECT...FOR UPDATE
thực sự là mộtWRITE
Khóa. Đó có thể là một lỗi trong chế độ ngủ đông hoặc chỉ là một quyết định thay vì triển khai "nhẹ nhàng hơn"READ
tùy chỉnh khóa,WRITE
"khó hơn" khóa được sử dụng để thay thế. Điều này chủ yếu không phá vỡ tính nhất quán, nhưng không giữ tất cả các quy tắc vớiREAD
ổ khóa. Bạn có thể chạy một số kiểm tra đơn giản vớiREAD
khóa và các giao dịch đang hoạt động lâu dài để tìm hiểu xem có nhiều giao dịch hơn có thể nhận đượcREAD
hay không khóa trên cùng một thực thể. Điều này có thể thực hiện được, trong khi vớiWRITE
thì không ổ khóa.
- LockModeType.PESSIMISTIC_FORCE_INCREMENT
- đây là một chế độ khóa hiếm khi được sử dụng khác. Tuy nhiên, đây là một tùy chọn mà bạn cần kết hợp
PESSIMISTIC
vàOPTIMISTIC
các cơ chế. Sử dụngPESSIMISTIC_WRITE
thuần túy sẽ thất bại trong trường hợp sau:- giao dịch A sử dụng khóa lạc quan và đọc thực thể E
- giao dịch B có được khóa WRITE trên thực thể E
- giao dịch B cam kết và giải phóng khóa E
- giao dịch A cập nhật E và cam kết
- trong bước 4, nếu cột phiên bản không được giao dịch B tăng lên, thì không có gì ngăn A ghi đè các thay đổi của B. Chế độ khóa
LockModeType.PESSIMISTIC_FORCE_INCREMENT
sẽ buộc giao dịch B cập nhật số phiên bản và khiến giao dịch A không thành công vớiOptimisticLockException
, mặc dù B đã sử dụng cách khóa bi quan.
- LockModeType.NONE
- đây là giá trị mặc định nếu các thực thể không cung cấp trường phiên bản. Nó có nghĩa là không có khóa được kích hoạt xung đột sẽ được giải quyết trên cơ sở nỗ lực cao nhất và sẽ không bị phát hiện. Đây là chế độ khóa duy nhất được phép bên ngoài giao dịch