Sử dụng đúng flush () trong JPA / Hibernate


110

Tôi đang thu thập thông tin về phương thức flush (), nhưng tôi không rõ khi nào sử dụng nó và cách sử dụng nó một cách chính xác. Từ những gì tôi đọc, hiểu biết của tôi là nội dung của bối cảnh liên tục sẽ được đồng bộ hóa với cơ sở dữ liệu, tức là phát hành các câu lệnh nổi bật hoặc làm mới dữ liệu thực thể.

Bây giờ tôi nhận được kịch bản sau với hai thực thể AB(trong mối quan hệ một đối một, nhưng không được JPA thực thi hoặc mô hình hóa). Acó PK tổng hợp, được đặt theo cách thủ công và cũng có trường IDENTITY được tạo tự động recordId. Điều này recordIdphải được ghi vào thực thể Bdưới dạng khóa ngoại cho A. Tôi đang tiết kiệm ABtrong một giao dịch duy nhất. Vấn đề là giá trị được tạo tự động A.recordIdkhông có sẵn trong giao dịch, trừ khi tôi thực hiện một cuộc gọi rõ ràng em.flush()sau khi gọi em.persist()tiếp A. (Nếu tôi có PK IDENTITY được tạo tự động thì giá trị được cập nhật trực tiếp trong thực thể, nhưng đó không phải là trường hợp ở đây.)

Có thể em.flush()gây hại gì khi sử dụng nó trong một giao dịch không?

Câu trả lời:


148

Có lẽ các chi tiết chính xác em.flush()phụ thuộc vào việc triển khai. Nói chung, các nhà cung cấp JPA như Hibernate có thể lưu vào bộ nhớ cache các lệnh SQL mà họ phải gửi đến cơ sở dữ liệu, thường là cho đến khi bạn thực sự cam kết giao dịch. Ví dụ, bạn gọi em.persist(), Hibernate nhớ rằng nó phải INSERT cơ sở dữ liệu, nhưng không thực sự thực hiện lệnh cho đến khi bạn thực hiện giao dịch. Afaik, điều này chủ yếu được thực hiện vì lý do hiệu suất.

Trong một số trường hợp, bạn muốn các lệnh SQL được thực thi ngay lập tức; nói chung khi bạn cần kết quả của một số tác dụng phụ, như khóa tự động tạo hoặc kích hoạt cơ sở dữ liệu.

Những gì em.flush()làm là làm trống bộ nhớ cache hướng dẫn SQL nội bộ và thực thi nó ngay lập tức vào cơ sở dữ liệu.

Điểm mấu chốt: không có tác hại nào được thực hiện, chỉ bạn có thể bị ảnh hưởng (nhỏ) về hiệu suất vì bạn đang ghi đè các quyết định của nhà cung cấp JPA về thời điểm tốt nhất để gửi hướng dẫn SQL đến cơ sở dữ liệu.


1
Những gì ông nói. Hành vi em.flush () lặp lại java.io.Flushable.flush () trong đó tất cả dữ liệu được lưu trong bộ đệm được gửi đến bất kỳ đích nào thích hợp.
Erik

4
nếu flush () gửi dữ liệu đến cơ sở dữ liệu? điều gì xảy ra nếu một ngoại lệ được ném ra sau đó? Người quản lý thực thể sẽ khôi phục mọi thứ? ngay cả dữ liệu được ghi trong lần xả đầu tiên?
Jaime Hablutzel

101
flush () gửi các hướng dẫn SQL đến cơ sở dữ liệu như INSERT, UPDATE, v.v. Nó sẽ không gửi COMMIT, vì vậy nếu bạn có ngoại lệ sau flush (), bạn vẫn có thể khôi phục hoàn chỉnh.
Flavio

17
Bạn có thể khôi phục DB, nhưng nó sẽ không khôi phục bất kỳ thay đổi nào đối với các đối tượng, ví dụ: 'phiên bản' tự động tăng, ID được tạo tự động, v.v. Hơn nữa, trình quản lý thực thể sẽ bị đóng sau khi khôi phục. Chỉ cần lưu ý rằng nếu bạn cố gắng 'hợp nhất' đối tượng vào một phiên khác, thì đặc biệt 'phiên bản' tự động tăng có thể gây ra lỗi OptimisticLockException.
Peter Davis

11
Ngoài việc kích hoạt các tác dụng phụ, một lý do khác để sử dụng flush () là nếu bạn muốn có thể đọc các tác động của một hoạt động trong cơ sở dữ liệu bằng JPQL / HQL (ví dụ: trong một thử nghiệm). JPA không thể sử dụng dữ liệu được lưu trong bộ nhớ cache khi thực hiện các truy vấn này, vì vậy chỉ những thứ thực sự trong DB mới được đọc.
sleske

2

Trên thực tế, em.flush()không chỉ gửi các lệnh SQL được lưu trong bộ nhớ cache. Nó cố gắng đồng bộ hóa ngữ cảnh liên tục với cơ sở dữ liệu bên dưới. Nó có thể gây tiêu tốn nhiều thời gian trên các quy trình của bạn nếu bộ nhớ cache của bạn chứa các bộ sưu tập cần được đồng bộ hóa.

Thận trọng khi sử dụng nó.


1

Em.flush () có thể gây hại gì khi sử dụng nó trong một giao dịch không?

Có, nó có thể giữ các ổ khóa trong cơ sở dữ liệu trong một thời gian dài hơn mức cần thiết.

Nói chung, khi sử dụng JPA, bạn ủy quyền quản lý giao dịch cho vùng chứa (hay còn gọi là CMT - sử dụng chú thích @Transactional về phương thức kinh doanh), có nghĩa là một giao dịch được tự động bắt đầu khi nhập phương thức và được cam kết / lùi lại ở cuối. Nếu bạn để EntityManager xử lý việc đồng bộ hóa cơ sở dữ liệu, việc thực thi câu lệnh sql sẽ chỉ được kích hoạt ngay trước khi cam kết, dẫn đến các khóa tồn tại trong thời gian ngắn trong cơ sở dữ liệu. Nếu không, các thao tác ghi được xả thủ công của bạn có thể giữ lại các khóa giữa quá trình xả thủ công và cam kết tự động có thể kéo dài theo thời gian thực hiện phương pháp còn lại.

Lưu ý rằng một số hoạt động tự động kích hoạt một phiên bản gốc: thực hiện một truy vấn gốc đối với cùng một phiên (trạng thái EM phải được xóa để truy vấn SQL có thể truy cập được), chèn các thực thể sử dụng id được tạo gốc (được tạo bởi cơ sở dữ liệu, vì vậy câu lệnh chèn phải được được kích hoạt do đó EM có thể truy xuất id đã tạo và quản lý đúng các mối quan hệ)

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.