Công dụng của session.flush () trong Hibernate


110

Khi chúng tôi đang cập nhật một bản ghi, chúng tôi có thể sử dụng session.flush()với Hibernate. Cần những flush()gì?

Câu trả lời:


138

Việc đẩy phiên làm việc buộc Hibernate phải đồng bộ hóa trạng thái trong bộ nhớ của Sessioncơ sở dữ liệu (tức là ghi các thay đổi vào cơ sở dữ liệu). Theo mặc định, Hibernate sẽ tự động gửi các thay đổi cho bạn:

  • trước khi thực hiện một số truy vấn
  • khi một giao dịch được cam kết

Cho phép xóa rõ ràng Sessionquyền kiểm soát tốt hơn có thể được yêu cầu trong một số trường hợp (để nhận ID được chỉ định, để kiểm soát kích thước của Phiên, ...).


8
Lưu ý rằng câu trả lời này mô tả hành vi DEFAULT Hibernate: hành vi xả có thể được thay đổi thông qua cài đặt Chế độ xả. Thông tin chi tiết có trong docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/… (phiên bản 3.5).
SteveT

1
Tôi đã tìm thấy tài liệu nơi nó nói chính xác những gì bạn đang nói nhưng tôi có câu hỏi rằng điều gì sẽ là ưu tiên có nghĩa là giả sử 1) Tôi có lớp nơi tôi đang lưu đối tượng bằng cách sử dụng mã id = session.save(obj);và giao dịch được cam kết ở dòng tiếp theo nhưng obj không được lưu cho DB, Tại sao? 2) Tôi đã lưu obj bằng cách sử dụng session.save(obj);commit và trong khi quay lại, tôi đã sử dụng return obj.getprimaryID();Trong trường hợp này, obj được lưu vào DB. Vậy tại sao lại có hành vi này?
Amogh

74

Như đã nói đúng trong các câu trả lời ở trên, bằng cách gọi flush() chúng ta buộc ngủ đông để thực thi các lệnh SQL trên Cơ sở dữ liệu. Nhưng hãy hiểu rằng những thay đổi chưa được "cam kết". Vì vậy, sau khi thực hiện xả và trước khi thực hiện cam kết, nếu bạn truy cập trực tiếp vào DB (ví dụ từ lời nhắc SQL) và kiểm tra các hàng đã sửa đổi, bạn sẽ KHÔNG thấy các thay đổi.

Điều này giống như việc mở 2 phiên lệnh SQL. Và những thay đổi được thực hiện trong 1 phiên sẽ không hiển thị với những người khác cho đến khi được cam kết.


12
Chà - những thay đổi có thể được nhìn thấy một chút. Ví dụ: một hàng không được cam kết có thể tạo một khóa trên hàng được chèn nhưng chưa được cam kết và trì hoãn việc cùng một hàng được chèn bởi một phiên khác cho đến khi giao dịch được cam kết hoặc khôi phục. Vì vậy, nó không hoàn toàn vô hình.
rghome

2
Tôi đã lướt khắp các trang web và đây là câu trả lời cuối cùng khiến tôi hiểu được. Cảm ơn.
Siddhartha

việc sử dụng .flush () trong vòng lặp for sau đó if commit () có xả ra ở cuối không?
Eildosa

@Kaushik Lele Điểm của flush () là gì nếu dữ liệu không hiển thị sau khi flush? Bạn có thể giải thích thêm về một số trường hợp sử dụng tốt hơn mà điều này có ích không?
java_geek

28

Tôi chỉ biết rằng khi chúng tôi gọi session.flush()các câu lệnh của chúng tôi được thực thi trong cơ sở dữ liệu nhưng không được cam kết.

Giả sử chúng ta không gọi flush()phương thức trên đối tượng session và nếu chúng ta gọi phương thức commit thì nó sẽ thực hiện nội bộ các câu lệnh trên cơ sở dữ liệu và sau đó cam kết.

commit=flush+commit (trong trường hợp chức năng)

Do đó, tôi kết luận rằng khi chúng ta gọi phương thức flush () trên đối tượng Session, thì nó không nhận được cam kết nhưng truy cập vào cơ sở dữ liệu và thực hiện truy vấn và cũng được khôi phục.

Để cam kết, chúng tôi sử dụng commit () trên đối tượng Giao dịch.


Bạn có thể cung cấp một số chi tiết về nhu cầu xả nước là gì?
java_geek

14

Việc đẩy phiên làm việc lấy dữ liệu hiện có trong phiên được đồng bộ hóa với dữ liệu trong cơ sở dữ liệu.

Thêm trên trang web Hibernate:

flush()rất hữu ích, bởi vì hoàn toàn không có đảm bảo về thời điểm Phiên thực hiện các lệnh gọi JDBC, chỉ thứ tự mà chúng được thực thi - ngoại trừ bạn sử dụng flush().


Bạn có thể cung cấp một kịch bản khi người dùng nên lo lắng về trình tự không? Sử dụng hibernate là làm cho những thứ liên quan đến DB trở nên minh bạch với người dùng. Khi chúng ta thực hiện "commit", quá trình xả nước sẽ tự động xảy ra. Kịch bản mà bạn sẽ thực hiện tuôn ra nhưng không cam kết là gì?
Kaushik Lele

1
@KaushikLele, bạn có thể tham khảo câu hỏi này stackoverflow.com/questions/37382872/…
GMsoF

10

Bạn có thể sử dụng flushđể buộc các ràng buộc xác thực phải được thực hiện và phát hiện ở một nơi đã biết hơn là khi giao dịch được cam kết. Có thể là như thếcommit được gọi ngầm bởi một số logic khung, thông qua logic khai báo, vùng chứa hoặc bởi một khuôn mẫu. Trong trường hợp này, bất kỳ ngoại lệ nào được ném ra có thể khó bắt và xử lý (nó có thể quá cao trong mã).

Ví dụ: nếu bạn save()là một đối tượng EmailAddress mới, có một ràng buộc duy nhất về địa chỉ, bạn sẽ không gặp lỗi cho đến khi bạn cam kết.

Việc gọi flush()buộc hàng phải được chèn, ném Ngoại lệ nếu có bản sao.

Tuy nhiên, bạn sẽ phải quay lại phiên sau khi ngoại lệ.


4

Tôi chỉ muốn kết hợp tất cả các câu trả lời được đưa ra ở trên và cũng liên hệ phương thức Flush () với Session.save () để có tầm quan trọng hơn

Hibernate save () có thể được sử dụng để lưu thực thể vào cơ sở dữ liệu. Chúng tôi có thể gọi phương thức này bên ngoài một giao dịch, đó là lý do tại sao tôi không thích phương pháp này để lưu dữ liệu. Nếu chúng tôi sử dụng điều này mà không có giao dịch và chúng tôi có xếp tầng giữa các thực thể, thì chỉ thực thể chính được lưu trừ khi chúng tôi xóa phiên.

flush (): Buộc phiên hoạt động. Nó được sử dụng để đồng bộ hóa dữ liệu phiên với cơ sở dữ liệu.

Khi bạn gọi session.flush (), các câu lệnh được thực thi trong cơ sở dữ liệu nhưng nó sẽ không được cam kết. Nếu bạn không gọi session.flush () và nếu bạn gọi session.commit (), phương thức commit () bên trong thực thi câu lệnh và cam kết.

Vì vậy, commit () = flush + commit. Vì vậy, session.flush () chỉ thực hiện các câu lệnh trong cơ sở dữ liệu (nhưng không thực hiện các cam kết) và các câu lệnh KHÔNG TRONG BỘ NHỚ nữa. Nó chỉ buộc phiên hoạt động.

Vài điểm quan trọng:

Chúng ta nên tránh lưu bên ngoài ranh giới giao dịch, nếu không các thực thể được ánh xạ sẽ không được lưu gây ra sự không nhất quán dữ liệu. Việc quên xóa phiên là điều rất bình thường vì nó không đưa ra bất kỳ ngoại lệ hoặc cảnh báo nào. Theo mặc định, Hibernate sẽ tự động xóa các thay đổi cho bạn: trước khi thực hiện một số truy vấn khi giao dịch được cam kết Cho phép xóa rõ ràng Phiên cung cấp quyền kiểm soát tốt hơn có thể được yêu cầu trong một số trường hợp (để được gán ID, kiểm soát kích thước của Phiên )


3

Các flush() phương pháp gây Hibernate để tuôn ra phiên. Bạn có thể cấu hình Hibernate để sử dụng chế độ xả cho phiên bằng setFlushMode()phương pháp sử dụng . Để có được chế độ xả cho phiên hiện tại, bạn có thể sử dụng getFlushMode()phương pháp. Để kiểm tra xem phiên có bị bẩn hay không, bạn có thể sử dụng isDirty()phương pháp. Theo mặc định, Hibernate quản lý việc xả các phiên.

Như đã nêu trong tài liệu:

https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/cha Chapter/flushing/Flushing.html

Đỏ bừng

Flushing là quá trình đồng bộ hóa trạng thái của bối cảnh liên tục với cơ sở dữ liệu bên dưới. The EntityManagervà Hibernate Sessionthể hiện một tập hợp các phương thức, qua đó nhà phát triển ứng dụng có thể thay đổi trạng thái liên tục của một thực thể.

Bối cảnh liên tục hoạt động như một bộ nhớ cache ghi lại giao dịch, xếp hàng đợi bất kỳ thay đổi trạng thái thực thể nào. Giống như bất kỳ bộ nhớ đệm ghi sau nào, các thay đổi được áp dụng đầu tiên trong bộ nhớ và được đồng bộ hóa với cơ sở dữ liệu trong thời gian lưu. Các hoạt động tuôn ra tận dụng mọi thay đổi trạng thái thực thể và chuyển nó thành một INSERT, UPDATEhoặc DELETEtuyên bố.

Chiến lược xả được đưa ra bởi flushMode của Phiên ngủ đông đang chạy hiện tại. Mặc dù JPA chỉ xác định hai chiến lược xả ( AUTOCOMMIT), nhưng Hibernate có một phổ rộng hơn nhiều loại xả:

  • ALWAYS: Đổ phiên trước mỗi truy vấn;
  • AUTO: Đây là chế độ mặc định và nó chỉ xóa Phiên khi cần thiết;
  • COMMIT: Phiên cố gắng trì hoãn quá trình xả cho đến khi Giao dịch hiện tại được cam kết, mặc dù nó cũng có thể xả sớm;
  • MANUAL: Phiên xả ra được ủy quyền cho ứng dụng, ứng dụng này phải gọi Session.flush()một cách rõ ràng để áp dụng các thay đổi ngữ cảnh liên tục.

Theo mặc định, Hibernate sử dụng AUTOchế độ xả để kích hoạt chế độ xả trong các trường hợp sau:

  • trước khi thực hiện một Giao dịch;
  • trước khi thực hiện truy vấn JPQL / HQL chồng chéo với các hành động của thực thể được xếp hàng đợi;
  • trước khi thực hiện bất kỳ truy vấn SQL gốc nào không có đồng bộ hóa đã đăng ký.

1

Gọi điện EntityManager#flushkhông có tác dụng phụ . Nó được sử dụng thuận tiện cho các loại thực thể có giá trị ID được tạo (giá trị trình tự): một ID như vậy chỉ khả dụng khi đồng bộ hóa với lớp bền vững bên dưới. Nếu ID này là bắt buộc trước khi giao dịch hiện tại kết thúc (ví dụ: cho mục đích ghi nhật ký), thì việc xóa phiên là bắt buộc.


0

Với phương pháp này, bạn gợi lên quá trình xả nước. Quá trình này đồng bộ hóa trạng thái cơ sở dữ liệu của bạn với trạng thái phiên của bạn bằng cách phát hiện các thay đổi trạng thái và thực thi các câu lệnh SQL tương ứng.

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.