แคชของเซสชันจะถูกเก็บไว้ด้วยกราฟวัตถุที่สัมพันธ์กัน โดยค่าเริ่มต้นเมื่อไฮเบอร์เนตโหลดวัตถุลูกค้าจากฐานข้อมูลวัตถุคำสั่งซื้อที่เกี่ยวข้องทั้งหมดจะถูกโหลดในเวลาเดียวกัน การใช้คลาสลูกค้าและการสั่งซื้อเป็นตัวอย่างสมมติว่า customer_id คีย์ต่างประเทศของตารางคำสั่งซื้อได้รับอนุญาตให้เป็นโมฆะ
Session的find() ใช้เพื่อดึงข้อมูลวัตถุลูกค้าทั้งหมดในฐานข้อมูล:
List customerLists=session.find("from Customer as c");
เมื่อเรียกใช้วิธี find() ด้านบน Hibernate จะสอบถามบันทึกทั้งหมดในตารางลูกค้าก่อนจากนั้นสอบถามตารางคำสั่งซื้อที่มีความสัมพันธ์อ้างอิงตาม ID ของแต่ละระเบียน Hibernate จะเรียกใช้คำสั่ง SELECT ต่อไปนี้ในทางกลับกัน:
เลือก * จากลูกค้า;
เลือก * จากคำสั่งซื้อที่ customer_id = 1;
เลือก * จากคำสั่งซื้อที่ customer_id = 2;
เลือก * จากคำสั่งซื้อที่ customer_id = 3;
เลือก * จากคำสั่งซื้อที่ customer_id = 4;
ผ่านคำสั่ง SELECT 5 ข้างต้นในที่สุดไฮเบอร์เนตก็โหลดวัตถุลูกค้า 4 รายการและวัตถุสั่งซื้อ 5 รายการซึ่งสร้างกราฟวัตถุที่เกี่ยวข้องในหน่วยความจำ
Hibernate ใช้นโยบายการค้นหาเริ่มต้นตอนนี้เมื่อดึงวัตถุคำสั่งซื้อที่เกี่ยวข้องกับลูกค้า มีข้อบกพร่องที่สำคัญสองประการในกลยุทธ์การค้นหานี้:
(1) จำนวนคำสั่งที่เลือกนั้นมีขนาดใหญ่เกินไปและเข้าถึงฐานข้อมูลบ่อยเกินไปจะส่งผลกระทบต่อประสิทธิภาพการดึงข้อมูล หากคุณต้องการสอบถามวัตถุลูกค้า N จากนั้นจะต้องดำเนินการคำสั่ง Query แบบสอบถาม N+1 นี่คือปัญหาการสืบค้น N+1 แบบคลาสสิก กลยุทธ์การค้นหานี้ไม่ได้ใช้ฟังก์ชั่นการสืบค้นการเชื่อมต่อของ SQL ตัวอย่างเช่นคำสั่ง SELECT 5 ข้างต้นสามารถเสร็จสมบูรณ์ได้อย่างสมบูรณ์โดยคำสั่ง 1 SELECT ต่อไปนี้:
เลือก * จากลูกค้าที่เหลือจากคำสั่งซื้อเข้าร่วมด้านนอก
บน customer.id = order.customer_id
คำสั่ง SELECT ด้านบนใช้ฟังก์ชั่นการสืบค้นด้านนอกด้านนอกของ SQL ซึ่งสามารถสอบถามบันทึกทั้งหมดของตารางลูกค้าและบันทึกของตารางคำสั่งซื้อการจับคู่ในคำสั่ง SELECT
(2) ในสถานการณ์ที่แอปพลิเคชันตรรกะจำเป็นต้องเข้าถึงวัตถุลูกค้าเท่านั้น แต่ไม่ได้สั่งซื้อวัตถุการโหลดวัตถุคำสั่งซื้อไม่จำเป็นอย่างสมบูรณ์ วัตถุคำสั่งซื้อที่ไม่จำเป็นเหล่านี้เสียพื้นที่หน่วยความจำจำนวนมาก
เพื่อแก้ปัญหาข้างต้น Hibernate ให้กลยุทธ์การค้นหาอีกสองกลยุทธ์: กลยุทธ์การค้นหาที่ล่าช้าและกลยุทธ์การค้นหาการเชื่อมต่อที่ปล่อยออกมาอย่างเร่งด่วน กลยุทธ์การดึงข้อมูลล่าช้าสามารถหลีกเลี่ยงการโหลดวัตถุที่เกี่ยวข้องซ้ำซ้อนซึ่งแอปพลิเคชันไม่จำเป็นต้องเข้าถึง กลยุทธ์การดึงการเชื่อมต่อด้านนอกด้านซ้ายอย่างเร่งด่วนทำให้การใช้ฟังก์ชันการสืบค้นการเชื่อมต่อภายนอกของ SQL เต็มรูปแบบและสามารถลดจำนวนคำสั่งที่เลือกได้
ปัญหาประสิทธิภาพจะต้องได้รับการพิจารณาเมื่อเข้าถึงฐานข้อมูล หลังจากตั้งค่าความสัมพันธ์แบบ 1 ถึงหลายครั้งปัญหา N +1 ในตำนานจะเกิดขึ้นในแบบสอบถาม
1) 1 ถึงหลาย ๆ ใน 1 ตารางสามารถพบวัตถุ N จากนั้นชุดที่เกี่ยวข้องกับวัตถุ N จะต้องนำออกมาดังนั้นแบบสอบถาม SQL ดั้งเดิมจะกลายเป็น N +1
2) จำนวนมากถึง 1 ถ้าคุณสอบถามวัตถุ M ในหลายฝ่ายแล้ววัตถุ 1 พรรคที่สอดคล้องกับวัตถุ M จะถูกนำออกมาและมันก็จะกลายเป็น M+1
1) lazy = true, hibernate3 ได้เริ่มต้นแล้วเป็น Lazy = true; เมื่อ lazy = true วัตถุที่เกี่ยวข้องจะไม่ถูกสอบถามทันที การดำเนินการแบบสอบถามจะเกิดขึ้นเฉพาะเมื่อวัตถุที่เกี่ยวข้อง (การเข้าถึงแอตทริบิวต์ของฟิลด์ที่ไม่ใช่ ID)
2) แคชระดับ 2 เมื่อวัตถุได้รับการอัปเดตน้อยกว่าการลบและเพิ่มมากกว่าการสืบค้นแอปพลิเคชันของแคชระดับ 2 จะไม่กลัวปัญหา N +1 เพราะแม้ว่าการสืบค้นแรกจะช้าแคชตีจะเร็วมากหลังจากนั้น
โซลูชันที่แตกต่างกันและความคิดที่แตกต่างกัน แต่สิ่งที่สองเพิ่งเกิดขึ้นกับการใช้ N +1 อีกครั้ง
3) แน่นอนคุณสามารถตั้งค่า fetch=join(annotation : @ManyToOne() @Fetch(FetchMode.JOIN))
ข้างต้นเป็นเรื่องเกี่ยวกับการสนทนาสั้น ๆ ของบทความนี้เกี่ยวกับปัญหา Hibernate N+1 และฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงหัวข้ออื่น ๆ ที่เกี่ยวข้องในเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!