1. การสืบค้นวัตถุเอนทิตี
การสืบค้นวัตถุเอนทิตีเป็นพื้นฐานของการสืบค้น HQL ในฐานะที่เป็นภาษาสืบค้นวัตถุมันแตกต่างจาก SQL ในระหว่างการดำเนินการแบบสอบถาม เนื้อหาในสตริงคิวรีควรถูกแทนที่ด้วยชื่อคลาสและชื่อแอตทริบิวต์คลาส วิธีการสืบค้นนี้ค่อนข้างง่าย ตราบใดที่คุณมีทักษะ SQL มันก็ง่ายมากที่จะใช้ HQL อย่างไรก็ตามมีปัญหาบางอย่างที่ต้องให้ความสนใจนั่นคือการสอบถามและการได้รับข้อมูลไม่ใช่วัตถุประสงค์และสิ่งที่ต้องพิจารณาคือวิธีการเขียนข้อความสอบถามที่มีประสิทธิภาพซึ่งเป็นจุดสนใจของการอภิปราย
1.N+1 ปัญหา
(1) ปัญหา N+1 คืออะไร
เมื่อฉันได้ยินคำนามนี้ครั้งแรกฉันอาจมีข้อสงสัย ฉันไม่เคยได้ยินปัญหา N+1 มาก่อน แล้วหมายความว่าอย่างไร? N+1 หมายถึงข้อมูล N ในตารางดังนั้นเมื่อได้รับข้อมูล N เหล่านี้คำสั่ง N+1 SQL จะถูกสร้างขึ้น การดำเนินการนี้เรียกว่า n+1 ที่นี่ 1 หมายถึงการออกคำสั่งที่ค้นหารายการ ID และ n หมายถึงการออกคำสั่ง N SQL ตาม ID เพื่อโหลดวัตถุที่เกี่ยวข้อง การดำเนินการแบบสอบถามแบบนี้ไม่มีประสิทธิภาพมากและมักจะถูกสร้างขึ้นในตัววนซ้ำ กล่าวคือถ้าเราแปลงผลลัพธ์การสืบค้นโดยตรงเป็นตัววนซ้ำปัญหานี้จะเกิดขึ้นดังนี้:
การทดสอบโมฆะสาธารณะ () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); /*** จะมีปัญหา n+1 สิ่งที่เรียกว่า N+1 มูลค่าคือการออกคำสั่ง n+1 SQL** 1: ออกคำสั่งที่สอบถามรายการ ID** n: ออกคำสั่ง N SQL ตาม ID และโหลดวัตถุที่เกี่ยวข้อง*/ iterator iter = session.createquery ("จากนักเรียน") ในขณะที่ (iter.hasnext ()) {นักเรียนนักเรียน = (นักเรียน) iter.next (); System.out.println (student.getName ()); } session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); -รหัสสอบถามข้างต้นจะทำให้เกิดปัญหา N+1 เนื่องจากแบบสอบถามจะถูกส่งคืนเป็นตัววนซ้ำเพื่อให้คำสั่ง SQL จะออกหากไม่ได้สร้างครั้งเดียว สิ่งนี้ส่วนใหญ่ขึ้นอยู่กับกลไกการสืบค้นของตัววนซ้ำซึ่งสืบค้นข้อมูลจากแคช หากข้อมูลไม่มีอยู่ในแคชข้อมูลจะถูกแปลงเป็นหน่วยความจำก่อนดังนั้นคำสั่ง SQL Query จะออกในเวลานี้ดังนั้นคำสั่ง SQL จะถูกสร้างขึ้นทุกครั้ง วิธีการเขียนนี้เป็นความผิดพลาดจริง ๆ และสามารถแก้ไขได้โดยใช้วิธีการอื่นเพื่อปรับให้เหมาะสม
(2) หลีกเลี่ยงปัญหา n+1
ปัญหาของ N+1 เกิดขึ้นเนื่องจากการใช้ซ้ำที่ไม่เหมาะสม แน่นอนวิธีอื่น ๆ สามารถใช้เพื่อหลีกเลี่ยงปัญหานี้ของ N+1 นี่คือวิธีรายการ ความแตกต่างที่ใหญ่ที่สุดระหว่างรายการและการวนซ้ำคือรายการใส่ข้อมูลลงในแคช แต่ไม่ได้ใช้แคช โดยค่าเริ่มต้นรายการจะออกคำสั่ง SQL ทุกครั้ง ก่อนที่จะใช้ซ้ำคุณสามารถใช้รายการเพื่อบันทึกข้อมูลลงในฐานข้อมูลเพื่อให้ซ้ำสามารถอ่านได้จากแคชเมื่อเข้าถึงข้อมูลหลีกเลี่ยงปัญหาที่เกิดขึ้น N+1 รหัสมีดังนี้:
การทดสอบโมฆะสาธารณะ () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); รายการนักเรียน = เซสชั่นสร้างศูนย์ ("จากนักเรียน") รายการ (); System.out.println ("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - จากนั้นไม่มีการใช้คำสั่ง SQL ตาม ID และข้อมูลในแคชจะถูกใช้โดยตรง * * วิธีการวนซ้ำหากข้อมูลมีอยู่ในแคชมันสามารถปรับปรุงประสิทธิภาพได้มิฉะนั้นปัญหา N+1 จะเกิดขึ้น System.out.println (student.getName ()); -ตัวอย่างข้างต้นหลีกเลี่ยงปัญหา N+1 เนื่องจากหลังจากดำเนินการรายการข้อมูลจะถูกวางไว้ในแคชเซสชัน (แคชระดับแรก) ดังนั้นเมื่อใช้ซ้ำคำสั่งจะออกเพื่อสอบถามรายการ ID จากนั้นข้อมูลที่เกี่ยวข้องจะถูกโหลดในแคชตาม ID หากมีการจับคู่ข้อมูลในแคชการสืบค้นคำสั่ง SQL ที่ใช้ ID จะไม่ถูกออกอีกต่อไปและข้อมูลในแคชจะถูกใช้โดยตรง วิธีการวนซ้ำสามารถปรับปรุงประสิทธิภาพได้หากข้อมูลมีอยู่ในแคชมิฉะนั้นจะเกิดปัญหา N+1
2. แบบสอบถามนำทางวัตถุ
การนำทางวัตถุหมายถึงการได้รับข้อมูลจากวัตถุอื่นตามการนำทางคุณลักษณะของวัตถุในวัตถุหนึ่ง สิ่งนี้สามารถทำให้คำสั่งการสืบค้นง่ายขึ้นและปรับวิธีการสืบค้นให้เหมาะสม หากเราปฏิบัติตามแนวคิดปกติของเราเราอาจเขียนและเขียนวัตถุของคลาสอื่นเพื่อให้ได้การดำเนินการของวัตถุอื่นซึ่งเป็นเรื่องยุ่งยากมากกว่าในการเปรียบเทียบคำสั่งการนำทางวัตถุ
@suppresswarnings ({"ไม่ได้ตรวจสอบ", "rawtypes"}) โมฆะสาธารณะ testQuery1 () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); // ส่งคืนรายการแอ็ตทริบิวต์ชุดผลลัพธ์ประเภทองค์ประกอบและประเภทแอตทริบิวต์ในคลาสเอนทิตีเป็นรายการนักเรียนเดียวกัน = เซสชั่น createquery ("จากนักเรียน s ที่ s.classes.name เช่น '%2%'") รายการ (); สำหรับ (iterator item = students.iterator (); ite.hasnext ();) {นักเรียน obj = (นักเรียน) ite.next (); System.out.println (obj.getName ()); } session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); -คำสั่ง Query ในตัวอย่างข้างต้นใช้วิธีการนำทางวัตถุ คำสั่ง Query เป็นแบบสอบถามข้อมูลจากวัตถุนักเรียน แต่แอตทริบิวต์วัตถุที่จะเปรียบเทียบมาจากแอตทริบิวต์ชื่อของวัตถุคลาส ในเวลานี้การใช้วิธีการสืบค้นวัตถุนำทางจะปรับปรุงประสิทธิภาพการสืบค้นอย่างมีนัยสำคัญและเพิ่มประสิทธิภาพคำสั่ง Query หากเป็นวิธีการสืบค้นธรรมดาอาจมีการสร้างคำสั่งการเชื่อมต่อจำนวนมากซึ่งซับซ้อนมาก
2. SQL แบบสอบถามดั้งเดิม
ค่าการสืบค้นดั้งเดิมคือการใช้คำสั่ง SQL เพื่อสอบถามและรับข้อมูลแทนที่จะใช้คำสั่ง HQL วิธีการใช้งานของมันนั้นง่ายมากคล้ายกับ HQL คุณจะต้องใช้วิธี createSqlQuery เพื่อสอบถาม จริง ๆ แล้วมันคล้ายกับวิธี createquery ของ HQL รหัสมีดังนี้:
โมฆะสาธารณะ testQeury () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); list list = session.createsqlQuery ("เลือก * จาก t_student") รายการ (); สำหรับ (iterator item = list.iterator (); ite.hasnext ();) {object [] obj = (object []) ite.next (); System.out.println (obj [0]+","+obj [1]); } session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); -รหัสด้านบนใช้วิธี createSqlQuery สตริงการสืบค้นในวิธีการคือคำสั่ง SQL มันใช้วิธีการสืบค้นสตริงพื้นฐาน ความแตกต่างคือ HQL มีชั้นของบรรจุภัณฑ์อื่นและกำหนดค่าตัวเลือกภาษาถิ่นที่สอดคล้องกันใน hibernate.cfg.xml เพื่อทำการแมปให้เสร็จสมบูรณ์
3. การเชื่อมต่อแบบสอบถาม
แบบสอบถามการเชื่อมต่อมักจะใช้ใน SQL เพื่อรับชุดของวัตถุหลายชิ้น ในหมู่พวกเขาสิ่งที่ใช้กันมากที่สุดคือการเข้าร่วมด้านใน, เข้าร่วมซ้าย, เข้าร่วมขวา, ฯลฯ ซึ่งอ้างถึงการสืบค้นเข้าร่วมด้านใน, แบบสอบถามเข้าร่วมด้านนอกซ้ายและแบบสอบถามเข้าร่วมด้านนอกขวา เนื้อหาที่พวกเขากลับมาระหว่างการสืบค้นคือผลิตภัณฑ์คาร์ทีเซียนระหว่างเอนทิตีเนื้อหาของแบบสอบถามและเนื้อหาบางส่วนของตารางด้านซ้ายเนื้อหาแบบสอบถามและเนื้อหาบางส่วนของตารางที่เหมาะสมและฟังก์ชั่นการสืบค้นนั้นมีประสิทธิภาพ วิธีการสืบค้นการเชื่อมต่อของ HQL และการสืบค้นการเชื่อมต่อของ SQL นั้นเหมือนกันในผลลัพธ์การสืบค้น แต่มีความแตกต่างเล็กน้อยในคำสั่งค้นหา
1. การเชื่อมต่อภายใน
คำค้นหา intrajoin ของ HQL สามารถสอบถามได้โดยใช้คำสั่งการเข้าร่วมภายในหรือคำสั่งเข้าร่วมและชุดผลลัพธ์ที่ได้คือผลิตภัณฑ์คาร์ทีเซียน เช่นเดียวกับการสืบค้นการเชื่อมต่อภายใน SQL การสืบค้นการเข้าร่วมของ HQL แบ่งออกเป็นสองประเภท: ชัดเจนและโดยนัย แบบสอบถามที่แสดงหมายถึงคำหลักเข้าร่วมในสตริงการสืบค้น แบบสอบถามโดยนัยไม่จำเป็นต้องเพิ่มการเข้าร่วมในสตริง
// การเชื่อมต่อภายใน @suppresswarnings ({"ไม่ถูกตรวจสอบ", "rawtypes"}) การทดสอบโมฆะสาธารณะ () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); // ส่งคืนรายการแอ็ตทริบิวต์ชุดผลลัพธ์ประเภทองค์ประกอบและประเภทแอตทริบิวต์ในคลาสเอนทิตีเป็นรายการเดียวกันกับนักเรียน = เซสชัน createquery ("เลือก s.name, c.name จากนักเรียนเข้าร่วม s.classes c") รายการ (); สำหรับ (iterator item = students.iterator (); ite.hasnext ();) {object [] obj = (object []) ite.next (); System.out.println (obj [0]); } session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); -
2. การเชื่อมต่อภายนอก
การเชื่อมต่อภายนอกจะถูกแบ่งออกเป็นการเชื่อมต่อด้านนอกซ้ายและแบบสอบถามการเชื่อมต่อด้านนอกขวา วิธีการสอบถามมีความคล้ายคลึงกัน แต่ผลลัพธ์การสืบค้นนั้นแตกต่างกัน พวกเขาเหมือนกับการเชื่อมต่อภายนอกของ SQL ในผลลัพธ์การสืบค้น ความแตกต่างคือวิธีการเขียน รหัสเฉพาะมีดังนี้:
@suppresswarnings ({"ไม่ได้ตรวจสอบ", "rawtypes"}) การทดสอบโมฆะสาธารณะ () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); // ส่งคืนรายการแอ็ตทริบิวต์ชุดผลลัพธ์ประเภทองค์ประกอบและประเภทแอตทริบิวต์ในคลาสเอนทิตีเป็นรายการเดียวกันกับนักเรียน = เซสชัน createquery ("เลือก S.Name, C.Name จากนักเรียน S Light เข้าร่วม S.classes C") รายการ (); สำหรับ (iterator item = students.iterator (); ite.hasnext ();) {object [] obj = (object []) ite.next (); System.out.println (obj [0]); } session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); -รหัสด้านบนใช้คำสั่ง Query Outer Outer ด้านซ้าย วิธีการสืบค้นด้านนอกขวาที่สอดคล้องกันนั้นคล้ายกับการเข้าร่วมด้านนอกด้านซ้าย เพียงแค่แปลงจากซ้ายไปขวา ข้อมูลการสืบค้นจะถูกบันทึกไว้ในวัตถุรายการและเนื้อหาแบบสอบถามสามารถรับได้ผ่านรายการ
4. แบบสอบถามการตั้งชื่อภายนอก
Query ชื่อภายนอกหมายถึงการเขียนคำสั่งแบบสอบถามลงในไฟล์การแมปและใช้แท็ก <Query> เพื่อกำหนดคำสั่ง HQL ในไฟล์การแมป ด้วยวิธีนี้คำสั่ง HQL ที่กำหนดสามารถรับรู้ฟังก์ชั่นการกำหนดค่าฟังก์ชั่น หากมีปัญหาเพียงแค่ต้องแก้ไขการกำหนดค่า หากคุณต้องการใช้คำสั่ง SQL นี้คุณสามารถใช้เมธอด session.getNamedQuery () ในโปรแกรมเพื่อรับสตริงการสืบค้น HQL ดังที่แสดงในตัวอย่างต่อไปนี้
1. คำสั่งค้นหาภายนอก
ตัวอย่างต่อไปนี้แสดงให้เห็นถึงแอปพลิเคชันของคำสั่งแบบสอบถามภายนอกเพิ่มแท็ก <Query> ลงในไฟล์การแมปเพิ่มแอตทริบิวต์ชื่อลงในแท็กและเพิ่มสตริงลงใน <! [CDATA []]> เพื่อให้สตริงคิวรีที่เกี่ยวข้องสามารถรับได้ในโปรแกรมตามแอตทริบิวต์ชื่อของแบบสอบถาม
<? xml เวอร์ชัน = "1.0"?> <! Doctype hibernate-mapping สาธารณะ "-// hibernate/hibernate mapping dtd 3.0 // en" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" table = "t_student"> <id name = "id"> <generator // id> <property name = "name"/> <property name = "createTime"> </property> <!-เพิ่มคอลัมน์คลาสใหม่ให้กับนักเรียนในด้านหนึ่ง <query name = "querystudent"> <! [cdata [เลือก S จากนักเรียน s ที่ s.id <? ]]> </utery> </hibernate-mapping>
การสืบค้นชื่อภายนอกทำให้คำสั่งค้นหาในไฟล์การแมปดังนั้นจึงสามารถพิจารณาสตริงการสืบค้นสาธารณะได้ นี่คือข้อได้เปรียบเพื่อให้สามารถรับและใช้ไฟล์โปรแกรมอื่น ๆ ได้ นอกจากนี้ยังเพิ่มความสะดวกในการปรับเปลี่ยนเป็นสตริงสาธารณะ
2. แอปพลิเคชันโปรแกรม
หลังจากกำหนดคำสั่งค้นหาภายนอกจำเป็นต้องใช้พวกเขาในโปรแกรม HQL จัดเตรียมวิธี getNameQuery เพื่อรับสตริงคำสั่งแบบสอบถามภายนอก ต้องเพิ่มชื่อเคอร์เซอร์ภายนอกในวิธีนี้ HQL จะสอบถามบล็อกคำสั่ง SQL ที่สอดคล้องกันตามชื่อเคอร์เซอร์ดังต่อไปนี้:
// คิวรีการตั้งชื่อภายนอก @suppresswarnings ({"ไม่ถูกตรวจสอบ", "rawtypes"}) การทดสอบโมฆะสาธารณะ () {เซสชันเซสชัน = null; ลอง {session = hibernateutils.getSession (); session.beginTransaction (); รายการนักเรียน = session.getNamedQuery ("querystudent"). setParameter (0, 10) .List (); สำหรับ (iterator item = students.ite.hasnext ();) {นักเรียน obj = (นักเรียน) ite.next (); System.out.println (obj.getName ()); } session.getTransaction (). commit (); } catch (exception e) {e.printstacktrace (); session.getTransaction (). ย้อนกลับ (); } ในที่สุด {hibernateutils.closesession (เซสชัน); -