2012-09-27 27 views
26

Trước hết hãy quên Hibernate. Giả sử rằng tôi có hai bảng, A & B. Hai giao dịch đang cập nhật cùng một bản ghi trong hai bảng này, nhưng txn 1 cập nhật B và sau đó A, trong khi txn 2 cập nhật A thì B. Đây là một ví dụ bế tắc điển hình. Cách phổ biến nhất để tránh điều này là xác định trước thứ tự của các tài nguyên có được. Ví dụ: chúng tôi nên cập nhật bảng A rồi B.Làm thế nào để Hibernate quyết định thứ tự cập nhật/chèn/xóa

Quay lại Hibernate. Khi chúng ta đang cập nhật rất nhiều thực thể trong một phiên, một khi tôi đang xóa phiên, các thay đổi của các thực thể khác nhau sẽ tạo ra các câu lệnh chèn/cập nhật/xóa tương ứng cho DB. Liệu Hibernate có một số thuật toán để quyết định thứ tự cập nhật giữa các thực thể? Nếu không, cách nào Hibernate được sử dụng để ngăn chặn tình trạng bế tắc được mô tả trong đoạn 1?

Nếu Hibernate duy trì thứ tự, làm cách nào tôi có thể biết hoặc kiểm soát thứ tự? Tôi không muốn cập nhật rõ ràng của tôi trong DB xung đột với Hibernate, và gây ra bế tắc.

Trả lời

29

Sự cố bạn mô tả không được xử lý bởi cơ sở dữ liệu và trải nghiệm của tôi cũng không được xử lý hoàn toàn bởi Hibernate.

Bạn phải thực hiện các bước rõ ràng để tránh sự cố đó.

Hibernate thực hiện một số công việc cho bạn. Theo câu trả lời trước, Hibernate đảm bảo rằng bên trong một tuôn ra bị cô lập chèn, xóa và cập nhật được sắp xếp theo cách đảm bảo rằng chúng sẽ được áp dụng theo thứ tự có thể đạt được.Xem performExecutions(EventSource session) trong lớp AbstractFlushingEventListener:

Execute tất cả các SQL (và bộ nhớ cache thứ hai cấp bản cập nhật) theo một thứ tự đặc biệt để hạn chế nước ngoài chủ chốt không thể bị vi phạm:

  1. Phụ trang, theo thứ tự chúng được thực hiện
  2. cập nhật
  3. xóa các yếu tố thu
  4. Đầu vào yếu tố thu
  5. Xóa, theo thứ tự chúng được thực hiện

Khi có ràng buộc duy nhất đó là rất quan trọng để biết thứ tự này, đặc biệt là nếu bạn muốn thay thế một đứa trẻ một-nhiều (xóa cũ/chèn mới) nhưng cả người già và đứa trẻ mới chia sẻ những ràng buộc duy nhất giống nhau (ví dụ cùng một địa chỉ email). Trong trường hợp này, bạn có thể cập nhật mục nhập cũ, thay vì xóa/chèn hoặc bạn có thể xóa sau khi xóa chỉ sau đó tiếp tục chèn. Để biết ví dụ chi tiết hơn, bạn có thể kiểm tra this article.

Lưu ý rằng nó không chỉ định thứ tự cập nhật. Kiểm tra mã Hibernate dẫn tôi nghĩ rằng thứ tự cập nhật sẽ phụ thuộc vào thứ tự mà các thực thể được thêm vào ngữ cảnh kiên trì, NOT thứ tự chúng đã được cập nhật. Điều đó có thể dự đoán được trong mã của bạn, nhưng việc đọc mã Hibernate đã không khiến tôi cảm thấy tôi sẽ dựa vào thứ tự đó.

Có ba giải pháp tôi có thể nghĩ:

  1. Hãy thử thiết lập hibernate.order_updatesđúng. Điều này sẽ giúp tránh deadlocks khi nhiều hàng trong cùng một bảng đang được cập nhật, nhưng sẽ không giúp đỡ với deadlocks trên nhiều bảng.
  2. Thực hiện giao dịch của bạn thực hiện khóa PESSIMISTIC_WRITE trên một trong các thực thể trước khi thực hiện bất kỳ cập nhật nào. Thực thể bạn sử dụng sẽ tùy thuộc vào tình huống cụ thể của bạn, nhưng miễn là bạn đảm bảo một thực thể được chọn nhất quán nếu có nguy cơ bế tắc, điều này sẽ chặn phần còn lại của giao dịch cho đến khi khóa được.
  3. Viết mã của bạn để nắm bắt deadlocks khi chúng xảy ra và thử lại một cách hợp lý. Thành phần quản lý việc thử lại khóa chết phải nằm ngoài ranh giới giao dịch hiện tại. Điều này là do phiên không thành công phải được đóng và giao dịch liên kết được hỗ trợ. Trong this article bạn có thể tìm thấy một ví dụ về thử lại AOP Aspect tự động.
+1

Xin vui lòng chấp nhận lời xin lỗi của tôi rằng, vì lý do không rõ tôi đã bỏ lỡ câu trả lời này trước :) Tôi tin rằng kết quả kiểm tra của bạn trong mã Hibernate thực sự đưa ra câu trả lời đáng tin cậy nhất cho đến bây giờ. Đề xuất tốt đặc biệt cho điểm 1 và 2 –

-1

Về ví dụ đầu tiên - loại công cụ này được xử lý bởi cơ sở dữ liệu (đọc thêm về mức cô lập giao dịch và chiến lược khóa của cơ sở dữ liệu của bạn). Có nhiều cách khác nhau để xử lý.

Đối với Hibernate, javadoc để org.hibernate.event.def.AbstractFlushingEventListener.performExecutions (EventSource) nói:

Execute tất cả cập nhật SQL và bộ nhớ cache cấp thứ hai, theo một thứ tự đặc biệt để hạn chế nước ngoài-key không thể bị vi phạm:

  1. Phụ trang, theo thứ tự chúng được thực hiện
  2. cập nhật xóa các yếu tố thu
  3. Đầu vào yếu tố thu
  4. .210
  5. Xóa, theo thứ tự chúng được thực hiện

tôi cho rằng đây là việc tối ưu hóa duy nhất của SQL thực hiện truy vấn Hibernate làm. Phần còn lại của vấn đề được xử lý bởi cơ sở dữ liệu.

+0

Tôi tin rằng công cụ mẫu đầu tiên hầu như KHÔNG thể xử lý bởi cơ sở dữ liệu. Đối với mức độ cô lập, từ sự hiểu biết của tôi, nó là nhiều hơn về cách thay đổi của một giao dịch được hiển thị cho người khác. Tuy nhiên, ngay cả đối với mức cô lập thấp nhất, hai giao dịch bằng văn bản cho cùng một hàng sẽ vẫn có khóa. Do đó nếu một txn cập nhật bản ghi A rồi B, và bản ghi B cập nhật txn khác rồi A, nó sẽ vẫn tạo bế tắc. Tốt nhất một DBMS có thể làm là để phát hiện bế tắc tiềm năng xảy ra. Tôi đang awared về Hibernate SQL lệnh thực hiện bạn đã đề cập, nhưng những gì tôi đang liên quan về về là về –

+0

thứ tự cập nhật giữa các thực thể. Nó sẽ khá ngạc nhiên nếu Hibernate không có bất kỳ xử lý nào và giả định rằng có thể được xử lý bởi DB (mà rõ ràng là không thực tế) –

+0

Oracle ví dụ bằng cách nào đó xử lý deadlocks "tự động phát hiện và giải quyết deadlocks bằng cách quay trở lại tuyên bố liên quan đến giao dịch phát hiện bế tắc ": http://www.oracle-base.com/articles/misc/deadlocks.php.Điều này có thể sẽ gây ra ngoại lệ JDBC, vì vậy bạn có thể thêm một số logic thử lại trong mã xử lý ngoại lệ. – Potejciak

Các vấn đề liên quan