Tại sao tôi cần Giao dịch ở chế độ Hibernate cho các hoạt động chỉ đọc?


107

Tại sao tôi cần Giao dịch ở chế độ Hibernate cho các hoạt động chỉ đọc?

Giao dịch sau có khóa DB không?

Mã mẫu để tìm nạp từ DB:

Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here

tx.commit() // why tx.commit? I don't want to write anything

Tôi có thể sử dụng session.close() thay thế tx.commit()không?


9
Giao dịch được yêu cầu bởi chính DB. Bạn có thể đọc về chế độ tự động gửi tại đây: community.jboss.org/wiki/…
Bhesh Gurung,

@BheshGurung tôi đoán chúng tôi yêu cầu Transcation chỉ dành cho hoạt động viết
user93796

4
Bạn đã đọc phần "gỡ lỗi tự động cam kết" trong liên kết chưa?
Bhesh Gurung,

Câu trả lời:


131

Bạn thực sự có thể có lý do để đánh dấu các giao dịch là chỉ đọc.

  1. Các giao dịch để đọc có thể trông thực sự lạ và thường mọi người không đánh dấu các phương pháp cho các giao dịch trong trường hợp này. Nhưng dù sao thì JDBC cũng sẽ tạo giao dịch, chỉ là nó sẽ hoạt động autocommit=truenếu tùy chọn khác không được đặt rõ ràng.
  2. Nhưng không có gì đảm bảo rằng phương thức của bạn không ghi vào cơ sở dữ liệu. Nếu bạn đánh dấu phương thức là @Transactional(readonly=true), Spring sẽ đặt giao dịch JDBC thành chế độ chỉ đọc, do đó bạn sẽ quyết định liệu có thực sự có thể ghi vào DB trong phạm vi của giao dịch này hay không. Nếu kiến ​​trúc của bạn cồng kềnh và một số thành viên trong nhóm có thể chọn đặt truy vấn sửa đổi ở nơi không mong đợi, cờ này sẽ chỉ bạn đến nơi có vấn đề.
  3. Ngoài ra, các giao dịch chỉ đọc có thể được tối ưu hóa bởi DB, nhưng điều này tất nhiên là DB cụ thể. Ví dụ: MySQL đã thêm hỗ trợ cho điều này chỉ trong InnoDB bắt đầu từ phiên bản 5.6.4.
  4. Nếu bạn không sử dụng JDBC trực tiếp mà là ORM, thì điều đó có thể có vấn đề. Ví dụ: cộng đồng Hibernate nói rằng làm việc bên ngoài giao dịch có thể gây ra hành vi không thể đoán trước. Điều này là do Hibernate sẽ mở giao dịch, nhưng nó sẽ không tự đóng, do đó kết nối sẽ được trả về Nhóm kết nối với giao dịch không được cam kết. Điều gì xảy ra sau đó? JDBC giữ im lặng, do đó đây là việc triển khai cụ thể (MySQL khôi phục giao dịch, Oracle afair cam kết điều đó). Điều này cũng có thể được cấu hình ở cấp độ Connection Pool (ví dụ: C3P0 cung cấp cho bạn tùy chọn như vậy, khôi phục theo mặc định).
  5. Một điều khác khi nói đến Hibernate, Spring đặt FlushMode thành MANUAL trong trường hợp giao dịch chỉ đọc, điều này dẫn đến các tối ưu hóa khác như không cần kiểm tra bẩn.
  6. Bạn có thể muốn ghi đè hoặc đặt mức cô lập giao dịch một cách rõ ràng. Điều này cũng ảnh hưởng đến các giao dịch đọc vì bạn thực hiện hoặc không muốn đọc các thay đổi chưa được cam kết, tiếp xúc với các lần đọc ảo, v.v.

Tóm lại - bạn có thể đi theo cả hai cách, nhưng bạn cần hiểu hậu quả.


Cảm ơn bạn đã trả lời. Tôi đang sử dụng chế độ ngủ đông (native hibernate, không phải jpa). Nhưng chế độ ngủ đông buộc tôi phải bắt đầu chuyển đổi trước khi thực hiện bất kỳ thao tác db nào. , nếu có như thế nào?
user93796

Cờ chỉ đọc thực sự được đặt cho kết nối, không phải cho chính giao dịch và bạn không thể truy cập nó thông qua Hibernate như vậy. Bạn cần sử dụng hỗ trợ Giao dịch mùa xuân và sử dụng chú thích hoặc cấu hình giao dịch dựa trên XML. Bằng cách đó, Spring có quyền sở hữu kết nối và quản lý giao dịch thay vì Hibernate.
Stanislav Bashkyrtsev

1
Giải thích rất tốt! Một bài viết khác của Mark Richards giải thích khá rõ những cạm bẫy của cờ chỉ đọc trong chú thích Giao dịch - ibm.com/developerworks/java/library/j-ts1/index.html .
Mahesh

48

Tất cả các câu lệnh cơ sở dữ liệu được thực thi trong ngữ cảnh của một giao dịch vật lý, ngay cả khi chúng tôi không khai báo rõ ràng các ranh giới giao dịch (BEGIN / COMMIT / ROLLBACK).

Nếu bạn không khai báo ranh giới giao dịch một cách rõ ràng, thì mỗi câu lệnh sẽ phải được thực hiện trong một ( autocommitchế độ) giao dịch riêng biệt . Điều này thậm chí có thể dẫn đến việc mở và đóng một kết nối cho mỗi câu lệnh trừ khi môi trường của bạn có thể xử lý ràng buộc kết nối trên mỗi luồng.

Khai báo một dịch vụ @Transactionalsẽ cung cấp cho bạn một kết nối trong toàn bộ thời lượng giao dịch và tất cả các câu lệnh sẽ sử dụng kết nối cách ly duy nhất đó. Cách này tốt hơn là không sử dụng các giao dịch rõ ràng ngay từ đầu.

Trên các ứng dụng lớn, bạn có thể có nhiều yêu cầu đồng thời và việc giảm tỷ lệ yêu cầu thu thập kết nối cơ sở dữ liệu chắc chắn sẽ cải thiện hiệu suất ứng dụng tổng thể của bạn.

JPA không thực thi các giao dịch trên các hoạt động đọc. Chỉ viết kết thúc bằng việc đưa ra một ngoại lệ bắt buộc giao dịch trong trường hợp bạn quên bắt đầu ngữ cảnh giao dịch. Tuy nhiên, luôn tốt hơn nếu khai báo ranh giới giao dịch ngay cả đối với các giao dịch chỉ đọc (trong Spring @Transactionalcho phép bạn đánh dấu các giao dịch chỉ đọc, điều này có lợi ích về hiệu suất lớn).


1
"... thì mỗi câu lệnh sẽ phải được thực hiện trong một giao dịch riêng biệt". Vùng chứa không tự động Xử lý hàng loạt ?
Arash

Xử lý hàng loạt là để sửa đổi, không phải để đọc dữ liệu. Và ngay cả như vậy, JDBC batching không được bật theo mặc định khi sử dụng JPA và Hibernate.
Vlad Mihalcea

1
Cảm ơn Vlad. Tôi đọc một số bài báo của bạn. Chúng thực sự hữu ích.
Arash

Stackoverflow.com/q/34797480/179850 này có vẻ hơi mâu thuẫn với khẳng định của bạn rằng các giao dịch chỉ đọc có lợi ích về hiệu suất tuyệt vời. Ít nhất, nó dường như không phải là trường hợp của chế độ ngủ đông.
nimai

Không, nó không. Đó là về thiết lập chỉ đọc, trong khi của tôi là về việc tránh tự động cam kết.
Vlad Mihalcea

17

Các giao dịch thực sự đặt các khóa trên cơ sở dữ liệu - các công cụ cơ sở dữ liệu tốt xử lý các khóa đồng thời theo cách hợp lý - và hữu ích với việc sử dụng chỉ đọc để đảm bảo rằng không có giao dịch nào khác thêm dữ liệu khiến chế độ xem của bạn không nhất quán. Bạn luôn muốn có một giao dịch (mặc dù đôi khi điều chỉnh mức độ cô lập là hợp lý, tốt nhất là không nên làm điều đó để bắt đầu); nếu bạn không bao giờ viết thư cho DB trong quá trình giao dịch của mình, thì cả việc cam kết và quay lại giao dịch đều diễn ra như nhau (và rất rẻ).

Bây giờ, nếu bạn may mắn và các truy vấn của bạn chống lại DB sao cho ORM luôn ánh xạ chúng đến các truy vấn SQL đơn lẻ, bạn có thể thoát khỏi các giao dịch rõ ràng , dựa vào hành vi tự động gửi tích hợp của DB, nhưng ORM là hệ thống tương đối phức tạp vì vậy sẽ không an toàn chút nào nếu dựa vào hành vi như vậy trừ khi bạn đi làm thêm nhiều việc để kiểm tra xem việc triển khai thực sự hoạt động như thế nào. Viết các ranh giới giao dịch rõ ràng trong đó dễ dàng hơn rất nhiều (đặc biệt nếu bạn có thể làm điều đó với AOP hoặc một số kỹ thuật điều khiển ORM tương tự; từ Java 7 trở đi, tôi cũng có thể sử dụng try-with-resources).


14

Không quan trọng bạn chỉ đọc hay không - cơ sở dữ liệu vẫn phải theo dõi tập kết quả của bạn, bởi vì các ứng dụng khách cơ sở dữ liệu khác có thể muốn ghi dữ liệu sẽ thay đổi tập kết quả của bạn.

Tôi đã thấy các chương trình bị lỗi giết chết các hệ thống cơ sở dữ liệu khổng lồ, vì chúng chỉ đọc dữ liệu, nhưng không bao giờ cam kết, buộc nhật ký giao dịch phát triển, vì DB không thể giải phóng dữ liệu giao dịch trước khi COMMIT hoặc ROLLBACK, ngay cả khi khách hàng không làm gì cả hàng giờ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.