ไฮเบอร์เนต: ความแตกต่างระหว่าง session.get และ session.load


88

จาก API ฉันเห็นว่ามันเกี่ยวข้องกับพร็อกซี แต่ฉันไม่พบข้อมูลมากมายเกี่ยวกับพร็อกซีและไม่เข้าใจความแตกต่างระหว่างการโทรsession.getและsession.load. ใครช่วยอธิบายหรือนำฉันไปที่หน้าอ้างอิงได้ไหม

ขอขอบคุณ!!

คำตอบ:


117

จากฟอรัม Hibernate :

จากหนังสือ Hibernate in Action น่าอ่าน ..


การดึงอ็อบเจ็กต์ด้วยตัวระบุข้อมูลโค้ดไฮเบอร์เนตต่อไปนี้ดึงอ็อบเจ็กต์ผู้ใช้จากฐานข้อมูล:

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

เมธอด get () เป็นวิธีพิเศษเนื่องจากตัวระบุระบุอินสแตนซ์ของคลาสเดียวโดยไม่ซ้ำกัน ดังนั้นจึงเป็นเรื่องปกติที่แอปพลิเคชันจะใช้ตัวระบุเป็นตัวจัดการที่สะดวกสำหรับวัตถุถาวร การดึงข้อมูลด้วยตัวระบุสามารถใช้แคชเมื่อดึงอ็อบเจ็กต์หลีกเลี่ยงการโดนฐานข้อมูลหากอ็อบเจ็กต์ถูกแคชไว้แล้ว ไฮเบอร์เนตยังมีวิธี load ():

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

วิธี load () เก่ากว่า get () ถูกเพิ่มใน API ของ Hibernate เนื่องจากคำขอของผู้ใช้ ความแตกต่างเป็นเรื่องเล็กน้อย:

ถ้า load () ไม่พบวัตถุในแคชหรือฐานข้อมูลจะมีข้อยกเว้น วิธี load () ไม่คืนค่า null เมธอด get () จะคืนค่า null หากไม่พบวัตถุ

วิธี load () อาจส่งคืนพร็อกซีแทนที่จะเป็นอินสแตนซ์ถาวรจริง พร็อกซีคือตัวยึดตำแหน่งที่ทริกเกอร์การโหลดอ็อบเจ็กต์จริงเมื่อเข้าถึงเป็นครั้งแรก ในทางกลับกัน get () ไม่ส่งคืนพร็อกซี การเลือกระหว่าง get () และ load () เป็นเรื่องง่าย: หากคุณมั่นใจว่ามีออบเจ็กต์ถาวรอยู่และการไม่มีอยู่จะถือว่าเป็นสิ่งพิเศษ load () เป็นตัวเลือกที่ดี หากคุณไม่แน่ใจว่ามีอินสแตนซ์ถาวรพร้อมตัวระบุที่กำหนดให้ใช้ get () และทดสอบค่าที่ส่งคืนเพื่อดูว่าเป็นโมฆะหรือไม่ การใช้ load () มีความหมายเพิ่มเติม: แอปพลิเคชันอาจดึงข้อมูลอ้างอิงที่ถูกต้อง (พร็อกซี) ไปยังอินสแตนซ์แบบถาวรโดยไม่ต้องกดปุ่มฐานข้อมูลเพื่อดึงข้อมูลสถานะถาวร ดังนั้น load () อาจไม่ทำให้เกิดข้อยกเว้นเมื่อไม่พบวัตถุถาวรในแคชหรือฐานข้อมูล ข้อยกเว้นจะถูกโยนทิ้งในภายหลังเมื่อมีการเข้าถึงพร็อกซี แน่นอนว่าการดึงวัตถุด้วยตัวระบุนั้นไม่ยืดหยุ่นเท่ากับการใช้การสืบค้นตามอำเภอใจ


1
ฉันกำลังแก้ไขปัญหาที่เซสชั่นรับ <T> () กำลังส่งคืนพร็อกซี!
Kent Boogaart

7
ขอบคุณมาก! ส่วนที่เป็นเงินสำหรับฉันคือ: "หาก load () ไม่พบวัตถุในแคชหรือฐานข้อมูลจะมีข้อยกเว้นเกิดขึ้นเมธอด get () จะคืนค่า null หากไม่พบวัตถุ"
คริส

15
JavaDoc สำหรับ Session.get กล่าวว่า: ส่งคืนอินสแตนซ์ถาวรของคลาสเอนทิตีที่กำหนดด้วยตัวระบุที่กำหนดหรือค่าว่างหากไม่มีอินสแตนซ์ถาวรดังกล่าว (หากอินสแตนซ์หรือพร็อกซีของอินสแตนซ์เชื่อมโยงกับเซสชันแล้วให้ส่งคืนอินสแตนซ์หรือพร็อกซีนั้น) ดังนั้นส่วนจากหนังสือที่ระบุว่า: "ในทางกลับกัน get () ไม่ส่งคืนพร็อกซี" ไม่ถูกต้อง.
Vicky

หากคุณใช้กลยุทธ์การจัดการธุรกรรมกับ daos ของคุณคุณอาจต้องการ get () มิฉะนั้นผู้โทรจะต้องดำเนินการในบริบทของเซสชันไฮเบอร์เนตแบบเปิดในกรณี load () ส่งคืนพร็อกซี ตัวอย่างเช่นหากคุณกำลังทำ MVC คอนโทรลเลอร์ของคุณอาจดำเนินการ dao.load () จากนั้นจึงเกิดข้อยกเว้นเมื่อพยายามเข้าถึงวัตถุพร็อกซีในภายหลังหากไม่มีเซสชันที่ถูกต้อง การทำ dao.get () จะส่งคืนวัตถุจริงไปยังคอนโทรลเลอร์โดยไม่คำนึงถึงเซสชัน (สมมติว่ามีอยู่)
dev

ปัญหาที่ @Vicky อธิบายไว้อาจทำให้ปวดหัวและฉันไม่เห็นประโยชน์ใด ๆ จากมัน ในบางกรณีฉันต้องการตัวระบุเพิ่มเติมสำหรับการสืบค้นพารามิเตอร์เพิ่มเติม แต่เนื่องจากพร็อกซีของอ็อบเจ็กต์อยู่ในเซสชันแล้ว getter of the identifier จะคืนค่า null เหตุใดพวกเขาจึงดึงพร็อกซีแทนอินสแตนซ์จริงหากพร็อกซีนั้นอยู่ในเซสชัน
djmj

15

อย่างน้อยที่สุดใน nhibernate session get (id) จะโหลดอ็อบเจ็กต์จากฐานข้อมูลในขณะที่ session.Load (id) จะสร้างพร็อกซีอ็อบเจ็กต์เท่านั้นโดยไม่ต้องออกจากเซิร์ฟเวอร์ของคุณ ทำงานเหมือนกับคุณสมบัติที่โหลดแบบขี้เกียจอื่น ๆ ใน POCO ของคุณ (หรือ POJOs :) จากนั้นคุณสามารถใช้พร็อกซีนี้เป็นการอ้างอิงถึงออบเจ็กต์เพื่อสร้างความสัมพันธ์ ฯลฯ

คิดว่ามันเหมือนกับมีวัตถุที่เก็บเฉพาะ Id และจะโหลดส่วนที่เหลือหากคุณต้องการ หากคุณเพียงแค่ผ่านมันไปรอบ ๆ เพื่อสร้างความสัมพันธ์ (เช่น FKs) id คือสิ่งที่คุณต้องการ


ดังนั้นคุณต้องการบอกว่า load (id) จะกดฐานข้อมูลก่อนเพื่อตรวจสอบว่าเป็น id ที่ถูกต้องหรือไม่และกว่าจะส่งคืนวัตถุพร็อกซีและเมื่อคุณสมบัติของวัตถุนี้ถูกเข้าถึงมันจะกระทบฐานข้อมูลอีกครั้ง? มันเป็นสถานการณ์ที่ไม่น่าเกิดขึ้นใช่หรือไม่? สองแบบสอบถามเพื่อโหลดวัตถุเดียว?
faisalbhagat

ไม่โหลด (id) จะไม่ตรวจสอบความถูกต้องของ id เลยดังนั้นจึงไม่มีการเดินทางไปกลับฐานข้อมูล ใช้เมื่อคุณแน่ใจว่าถูกต้องเท่านั้น
Jorge Alves

9

session.load () จะส่งคืน "พร็อกซี" (คำไฮเบอร์เนต) เสมอโดยไม่ต้องกดปุ่มฐานข้อมูล ใน Hibernate พร็อกซีคืออ็อบเจกต์ที่มีค่าตัวระบุที่กำหนดคุณสมบัติของมันยังไม่ได้ถูกเตรียมใช้งาน แต่ดูเหมือนเป็นวัตถุปลอมชั่วคราว หากไม่พบแถวก็จะพ่น ObjectNotFoundException

session.get () ตีฐานข้อมูลและส่งคืนวัตถุจริงเสมอซึ่งเป็นวัตถุที่แสดงแถวฐานข้อมูลไม่ใช่พร็อกซี หากไม่พบแถวจะส่งคืนค่าว่าง

ประสิทธิภาพด้วยวิธีการเหล่านี้ยังสร้างความแตกต่าง ระหว่างสอง ...


ข้อความเดียวกับในmkyong.com/hibernate/… (แต่ไม่รู้ว่าใครขึ้นก่อน)
bish

3

อีกหนึ่งจุดพิเศษ ::

รับเมธอดของคลาส Hibernate Session จะคืนค่า null หากไม่พบอ็อบเจ็กต์ในแคชและบนฐานข้อมูล ในขณะที่วิธี load () จะพ่น ObjectNotFoundException หากไม่พบอ็อบเจ็กต์บนแคชและบนฐานข้อมูล แต่ไม่ส่งคืนค่าว่าง


2

ผลทางอ้อมอย่างหนึ่งของการใช้ "load" แทน "get" คือการล็อกการมองโลกในแง่ดีโดยใช้แอตทริบิวต์ version อาจไม่ได้ผลตามที่คุณคาดหวัง หากการโหลดเพียงสร้างพร็อกซีและไม่ได้อ่านจากฐานข้อมูลคุณสมบัติเวอร์ชันจะไม่ถูกโหลด เวอร์ชันจะโหลดก็ต่อเมื่อ / หากคุณอ้างถึงคุณสมบัติบนวัตถุในภายหลังโดยเรียกใช้การเลือก ในระหว่างนี้เซสชันอื่นสามารถอัปเดตออบเจ็กต์ได้และเซสชันของคุณจะไม่มีเวอร์ชันดั้งเดิมที่จำเป็นต้องทำการตรวจสอบการล็อกในแง่ดีดังนั้นการอัปเดตเซสชันของคุณจะเขียนทับการอัปเดตของเซสชันอื่นโดยไม่มีคำเตือน

นี่คือความพยายามในการร่างสถานการณ์นี้โดยมีสองเซสชันที่ทำงานกับออบเจ็กต์ที่มีตัวระบุเดียวกัน เวอร์ชันเริ่มต้นสำหรับอ็อบเจ็กต์ใน DB คือ 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]

จริงๆแล้วเราต้องการให้การกระทำของเซสชัน 1 ล้มเหลวด้วยข้อยกเว้นการล็อกในแง่ดี แต่จะสำเร็จที่นี่

การใช้ "get" แทน "load" จะช่วยแก้ปัญหาได้เนื่องจาก get จะออกการเลือกทันทีและหมายเลขเวอร์ชันจะถูกโหลดตามเวลาที่ถูกต้องสำหรับการตรวจสอบการล็อกในแง่ดี


0

นอกจากนี้เราต้องระมัดระวังในขณะที่ใช้โหลดเนื่องจากจะทำให้เกิดข้อยกเว้นหากไม่มีวัตถุ เราต้องใช้ก็ต่อเมื่อแน่ใจว่ามีวัตถุนั้นอยู่


0

ดูคำอธิบายที่ยอดเยี่ยมได้ที่http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load ():
มันจะส่งคืน "พร็อกซี" (คำไฮเบอร์เนต) เสมอโดยไม่ กดปุ่มฐานข้อมูล
ใน Hibernate พร็อกซีคืออ็อบเจกต์ที่มีค่าตัวระบุที่กำหนดคุณสมบัติของมันยังไม่ได้ถูกเตรียมใช้งาน แต่ดูเหมือนเป็นวัตถุปลอมชั่วคราว
มันจะส่งคืนอ็อบเจ็กต์พร็อกซีพร้อมกับค่าเอกลักษณ์ที่กำหนดเสมอแม้ค่าเอกลักษณ์จะไม่มีอยู่ในฐานข้อมูล อย่างไรก็ตามเมื่อคุณพยายามเริ่มต้นพร็อกซีโดยดึงคุณสมบัติจากฐานข้อมูลมันจะเข้าสู่ฐานข้อมูลด้วยคำสั่งที่เลือก หากไม่พบแถว ObjectNotFoundException จะโยน
session.get ():
มันจะเข้าสู่ฐานข้อมูลเสมอ (หากไม่พบในแคช) และส่งคืนวัตถุจริงซึ่งเป็นวัตถุที่แสดงแถวฐานข้อมูลไม่ใช่พร็อกซี
หากไม่พบแถวจะส่งคืนค่าว่าง


0

load () ไม่พบวัตถุจากแคชหรือฐานข้อมูลมีข้อยกเว้นเกิดขึ้นและวิธี load () จะไม่คืนค่า null

get () วิธีการคืนค่า null ถ้าไม่พบวัตถุ วิธี load () อาจส่งคืนพร็อกซีแทนอินสแตนซ์ถาวรจริง get () ไม่ส่งคืนพร็อกซี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.