Hibernate: Sự khác biệt giữa session.get và session.load


88

Từ API, tôi có thể thấy nó có liên quan gì đó đến proxy. Nhưng tôi không thể tìm thấy nhiều thông tin về proxy và không hiểu sự khác biệt giữa gọi session.getsession.load. Ai đó có thể vui lòng giải thích hoặc hướng dẫn tôi đến một trang tham khảo?

Cảm ơn bạn!!

Câu trả lời:


117

Từ diễn đàn Hibernate :

Điều này từ cuốn sách Hibernate in Action. Tốt một người đọc này ..


Truy xuất đối tượng theo mã định danh Đoạn mã Hibernate sau đây truy xuất đối tượng Người dùng từ cơ sở dữ liệu:

User user = (User) session.get(User.class, userID);

Phương thức get () đặc biệt vì mã định danh xác định duy nhất một thể hiện của một lớp. Do đó, thông thường các ứng dụng sử dụng mã định danh như một trình xử lý thuận tiện cho một đối tượng liên tục. Truy xuất bằng mã định danh có thể sử dụng bộ đệm khi truy xuất một đối tượng, tránh một lần truy cập cơ sở dữ liệu nếu đối tượng đã được lưu trong bộ đệm. Hibernate cũng cung cấp một phương thức load ():

User user = (User) session.load(User.class, userID);

Phương thức load () cũ hơn; get () đã được thêm vào API của Hibernate do yêu cầu của người dùng. Sự khác biệt là nhỏ:

Nếu load () không thể tìm thấy đối tượng trong bộ nhớ cache hoặc cơ sở dữ liệu, một ngoại lệ sẽ được đưa ra. Phương thức load () không bao giờ trả về null. Phương thức get () trả về null nếu không tìm thấy đối tượng.

Phương thức load () có thể trả về một proxy thay vì một phiên bản liên tục thực sự. Proxy là một trình giữ chỗ kích hoạt tải đối tượng thực khi nó được truy cập lần đầu tiên; Mặt khác, get () không bao giờ trả về một proxy. Lựa chọn giữa get () và load () rất dễ dàng: Nếu bạn chắc chắn rằng đối tượng liên tục tồn tại và sự không tồn tại sẽ được coi là đặc biệt, load () là một lựa chọn tốt. Nếu bạn không chắc chắn có một trường hợp liên tục với số nhận dạng đã cho, hãy sử dụng get () và kiểm tra giá trị trả về để xem nó có rỗng không. Sử dụng load () có một ngụ ý khác: Ứng dụng có thể truy xuất một tham chiếu hợp lệ (một proxy) đến một phiên bản liên tục mà không cần nhấn vào cơ sở dữ liệu để truy xuất trạng thái liên tục của nó. Vì vậy, load () có thể không ném ra một ngoại lệ khi nó không tìm thấy đối tượng liên tục trong bộ nhớ cache hoặc cơ sở dữ liệu; ngoại lệ sẽ được đưa ra sau đó, khi proxy được truy cập. Tất nhiên, việc truy xuất một đối tượng bằng số nhận dạng không linh hoạt bằng việc sử dụng các truy vấn tùy ý.


1
Tôi đang gỡ lỗi một sự cố ngay bây giờ khi session.Get <T> () đang trả về một proxy!
Kent Boogaart

7
Cảm ơn rất nhiều! Phần tiền đối với tôi là: "Nếu load () không thể tìm thấy đối tượng trong bộ nhớ cache hoặc cơ sở dữ liệu, một ngoại lệ sẽ được ném ra. Phương thức get () trả về null nếu không tìm thấy đối tượng."
Chris

15
JavaDoc cho Session.get cho biết: Trả về phiên bản liên tục của lớp thực thể nhất định với số nhận dạng đã cho hoặc null nếu không có phiên bản liên tục như vậy. (Nếu phiên bản, hoặc một proxy cho phiên bản, đã được liên kết với phiên, hãy trả lại phiên bản hoặc proxy đó.) Vì vậy, phần trong cuốn sách có nội dung: "Mặt khác, get () không bao giờ trả về một proxy." không đúng.
Vicky

nếu bạn đang sử dụng chiến lược quản lý giao dịch với daos của mình, bạn có thể thích get () hơn. nếu không, người gọi cũng sẽ cần phải thực thi trong ngữ cảnh của một phiên ngủ đông mở trong trường hợp load () trả về proxy. ví dụ: nếu bạn đang thực hiện MVC, bộ điều khiển của bạn có thể thực thi dao.load () và sau đó ném một ngoại lệ khi cố gắng truy cập đối tượng proxy sau này nếu không có phiên hợp lệ. doing dao.get () sẽ trả về đối tượng thực tế cho bộ điều khiển bất kể phiên (giả sử nó tồn tại)
dev

Vấn đề mà @Vicky mô tả có thể gây đau đầu và tôi không thấy bất kỳ lợi ích nào của nó. Trong một số trường hợp, tôi cũng cần số nhận dạng cho các truy vấn được tham số hóa thêm. Nhưng vì một proxy của đối tượng đã có trong phiên, nên getter của số nhận dạng trả về null. Tại sao họ truy xuất proxy thay vì phiên bản thực nếu proxy đó ở trong phiên?
djmj

15

Vâng, ít nhất trong nhibernate, session.Get (id) sẽ tải đối tượng từ cơ sở dữ liệu, trong khi session.Load (id) chỉ tạo một đối tượng proxy cho nó mà không cần rời khỏi máy chủ của bạn. Hoạt động giống như mọi thuộc tính được tải chậm khác trong POCO của bạn (hoặc POJO :). Sau đó, bạn có thể sử dụng proxy này làm tham chiếu đến chính đối tượng để tạo mối quan hệ, v.v.

Hãy nghĩ về nó giống như có một đối tượng chỉ giữ Id và nó sẽ tải phần còn lại nếu bạn cần. Nếu bạn chỉ chuyển nó xung quanh để tạo mối quan hệ (như FK), thì id là tất cả những gì bạn cần.


vì vậy bạn muốn nói tải (id) trước tiên sẽ đánh vào cơ sở dữ liệu để kiểm tra xem nó có phải là id hợp lệ hay không và than sẽ trả về đối tượng proxy và khi các thuộc tính của đối tượng này được truy cập, nó sẽ truy cập lại vào cơ sở dữ liệu? nó không phải là một kịch bản khó xảy ra? hai truy vấn để tải một đối tượng?
faisalbhagat

Không, tải (id) sẽ hoàn toàn không xác thực id nên không có chuyến đi khứ hồi nào đến DB. Chỉ sử dụng nó khi bạn chắc chắn rằng nó hợp lệ.
Jorge Alves

9

session.load () sẽ luôn trả về một “proxy” (thuật ngữ Hibernate) mà không cần nhấn vào cơ sở dữ liệu. Trong Hibernate, proxy là một đối tượng có giá trị định danh đã cho, các thuộc tính của nó vẫn chưa được khởi tạo, nó giống như một đối tượng giả tạm thời. Nếu không tìm thấy hàng nào, nó sẽ ném ra một ObjectNotFoundException.

session.get () luôn đánh vào cơ sở dữ liệu và trả về đối tượng thực, một đối tượng đại diện cho hàng cơ sở dữ liệu, không phải proxy. Nếu không tìm thấy hàng, nó trả về null.

Hiệu suất với các phương pháp này cũng tạo ra sự khác biệt. giữa hai ...


3

Thêm một điểm nữa ::

phương thức get của lớp Hibernate Session trả về null nếu đối tượng không được tìm thấy trong bộ đệm cũng như trên cơ sở dữ liệu. trong khi phương thức load () ném ObjectNotFoundException nếu đối tượng không được tìm thấy trên bộ nhớ cache cũng như trên cơ sở dữ liệu nhưng không bao giờ trả về null.


2

Một hậu quả gián tiếp của việc sử dụng "load" thay vì "get" là khóa lạc quan bằng cách sử dụng thuộc tính phiên bản có thể không hoạt động như bạn mong đợi. Nếu tải chỉ tạo ra một proxy và không đọc từ cơ sở dữ liệu, thì thuộc tính phiên bản sẽ không được tải. Phiên bản sẽ chỉ được tải khi / nếu sau này bạn tham chiếu đến một thuộc tính trên đối tượng, kích hoạt một lựa chọn. Trong thời gian chờ đợi, một phiên khác có thể cập nhật đối tượng và phiên của bạn sẽ không có phiên bản gốc mà nó cần thực hiện kiểm tra khóa lạc quan - do đó, bản cập nhật của phiên của bạn sẽ ghi đè lên bản cập nhật của phiên khác mà không có cảnh báo.

Đây là một nỗ lực để phác thảo kịch bản này với hai phiên làm việc với một đối tượng có cùng số nhận dạng. Phiên bản ban đầu cho đối tượng trong DB là 10.

Session 1                  Session 2
---------                  ---------
Load object
Wait a while..   
                           Load object
                           Modify object property
                           [triggers db 'select' -
                            version read as 10]
                           Commit
                           [triggers db update,
                            version modified to 11]
Modify object property
  [triggers db 'select' -
  version read as 11]
Commit
  [triggers db update,
  version modified to 12]

Chúng tôi thực sự muốn cam kết của phiên 1 không thành công với một ngoại lệ khóa lạc quan, nhưng nó sẽ thành công ở đây.

Sử dụng "get" thay vì "load" sẽ giải quyết được vấn đề vì get sẽ ngay lập tức đưa ra một lựa chọn và số phiên bản sẽ được tải vào đúng thời điểm để kiểm tra khóa lạc quan.


0

Ngoài ra, chúng ta phải cẩn thận trong khi sử dụng tải vì nó sẽ ném ra một ngoại lệ nếu đối tượng không có mặt. Chúng tôi phải sử dụng nó chỉ khi chúng tôi chắc chắn rằng đối tượng đó tồn tại.


0

Một lời giải thích tuyệt vời được tìm thấy tại http://www.mkyong.com/hibernate/dierence-between-session-get-and-session-load
session.load ():
Nó sẽ luôn trả về một “proxy” (cụm từ Hibernate) mà không có đánh vào cơ sở dữ liệu.
Trong Hibernate, proxy là một đối tượng có giá trị định danh đã cho, các thuộc tính của nó vẫn chưa được khởi tạo, nó giống như một đối tượng giả tạm thời.
Nó sẽ luôn trả về một đối tượng proxy với giá trị nhận dạng đã cho, thậm chí giá trị nhận dạng không tồn tại trong cơ sở dữ liệu. Tuy nhiên, khi bạn cố gắng khởi tạo proxy bằng cách truy xuất các thuộc tính của nó từ cơ sở dữ liệu, nó sẽ nhấn vào cơ sở dữ liệu với câu lệnh select. Nếu không tìm thấy hàng nào, một ObjectNotFoundException sẽ ném.
session.get ():
Nó luôn đánh vào cơ sở dữ liệu (nếu không tìm thấy trong bộ nhớ cache) và trả về đối tượng thực, một đối tượng đại diện cho hàng cơ sở dữ liệu, không phải proxy.
Nếu không tìm thấy hàng, nó trả về null.


0

load () không thể tìm thấy đối tượng từ bộ nhớ cache hoặc cơ sở dữ liệu, một ngoại lệ được ném ra và phương thức load () không bao giờ trả về null.

Phương thức get () trả về null nếu không thể tìm thấy đối tượng. Phương thức load () có thể trả về một proxy thay vì một phiên bản liên tục thực sự get () không bao giờ trả về proxy.

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.