การวิจัยหลักในบทความนี้คือเนื้อหาที่เกี่ยวข้องของการสืบค้น HIBernate HQL ดังต่อไปนี้
Hibernate Query Language (HQL) เป็นคำสั่งค้นหาเชิงวัตถุอย่างสมบูรณ์พร้อมฟังก์ชั่นการสืบค้นที่ทรงพลังมาก มันมีความหลากหลายความสัมพันธ์และลักษณะอื่น ๆ HQL Query ยังเป็นวิธีการสืบค้นที่แนะนำอย่างเป็นทางการโดย Hibernate
ต่อไปเราวิเคราะห์วิธีการสืบค้นที่เกี่ยวข้องผ่านกรณีศึกษา
ชั้นเรียน. java:
ชั้นเรียนสาธารณะคลาส {/*คลาส ID*/ID INT ส่วนตัว;/*ชื่อคลาส*/ชื่อสตริงส่วนตัว;/*ความสัมพันธ์ระหว่างชั้นเรียนและนักเรียน*/ชุดส่วนตัว <Tudent> นักเรียน; // omit setter และวิธีการ getter}student.java:
นักเรียนชั้นเรียนสาธารณะ {/*ID นักเรียน*/ID INT ส่วนตัว;/*ชื่อนักเรียน*/ชื่อสตริงส่วนตัว;/*ความสัมพันธ์ระหว่างนักเรียนและชั้นเรียน*/ชั้นเรียนส่วนตัว; // omit setter และวิธีการ getter}classes.hbm.xml:
<? xml เวอร์ชัน = "1.0"?> <! Doctype hibernate-mapping สาธารณะ "-// hibernate/hibernate mapping dtd 3.0 // en" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" <class name = "classes" table = "t_classes" lazy = "false"> <id name = "id"> <generator/generator/> </id> <property name = "name"/> <! </set> </class> </hibernate-mapping>
student.hbm.xml:
<? 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"/> <!-การแมปแบบหลายต่อหนึ่งเพิ่มคีย์ต่างประเทศลงในหลาย ๆ จุด->
/*ส่งคืนรายการแอ็ตทริบิวต์ชุดผลลัพธ์ประเภทองค์ประกอบและประเภทแอตทริบิวต์ในคลาสเอนทิตีนั้นเหมือนกัน*/ รายการ <String> นักเรียน = เซสชัน Createquery ("เลือกชื่อจากนักเรียน") รายการ (); /*travel*/ for (iterator <string> iter = students.iterator (); iter.hasnext ();) {string name = (string) iter.next (); System.out.println (ชื่อ); -หมายเหตุ: เมื่อสอบถามแอตทริบิวต์เดียวชุดที่ส่งคืนเป็นคอลเลกชันและประเภทขององค์ประกอบการรวบรวมคือประเภทของแอตทริบิวต์
/*Query Properties หลายคุณสมบัติส่งคืนอาร์เรย์วัตถุ*/ list <object []> students = session.createquery ("เลือก ID, ชื่อจากนักเรียน"). list (); /*transip*/ for (iterator <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); -หมายเหตุ: การสอบถามหลายแอตทริบิวต์ส่งคืนคอลเลกชันของอาร์เรย์วัตถุประเภท นี่เป็นเรื่องง่ายที่จะเข้าใจ เมื่อสอบถามแอตทริบิวต์เดียวคือประเภทองค์ประกอบคอลเลกชันที่ส่งคืนมันเป็นประเภทของแอตทริบิวต์ แต่สิ่งที่เกี่ยวกับหลายประเภท? นั่นจะต้องเป็นอาร์เรย์วัตถุในการประมวลผลนั่นคือวัตถุ []
/*เราตั้งค่าตัวสร้างที่สอดคล้องกันสำหรับวัตถุเอนทิตีและจากนั้นเราสามารถส่งคืนประเภทวัตถุวัตถุเอนทิตีโดยการสอบถามวัตถุ*/ รายการนักเรียน = เซสชัน. Createquery ("เลือกนักเรียนใหม่ (id, ชื่อ) จากนักเรียน") รายการ (); /*Travel*/ for (iterator iter = students.iterator (); iter.hasnext ();) {นักเรียนนักเรียน = (นักเรียน) iter.next (); System.out.println (student.getId () + "," + student.getName ()); -หมายเหตุ: นอกเหนือจากวิธีที่สองเราส่งคืนอาร์เรย์วัตถุเรายังสามารถตั้งค่าตัวสร้างที่สอดคล้องกันสำหรับวัตถุเอนทิตีจากนั้นสอบถามวัตถุโดยการสอบถามวัตถุจากนั้นส่งคืนคอลเลกชันประเภทเอนทิตี
/*นามแฝงสามารถใช้*/ list <object []> students = session.createquery ("เลือก S.ID, S.Name จากนักเรียน S"). list (); /*transip*/ for (iterator <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); - /*return เป็นคอลเลกชันประเภทวัตถุเอนทิตี*/ รายการ <student> นักเรียน = session.createquery ("จากนักเรียน") รายการ (); /*transip*/ for (iterator <student> iter = students.iterator (); iter.hasnext ();) {นักเรียนนักเรียน = (นักเรียน) iter.next (); System.out.println (student.getName ()); -หมายเหตุ: เอนทิตีแบบสอบถามสามารถใช้รูปแบบของชื่อจากคลาสได้โดยตรง
/*ใช้เลือกเพื่อใช้นามแฝง*/ รายการ <student> นักเรียน = เซสชัน. createquery ("เลือก S จากนักเรียน s") รายการ (); /*transip*/ for (iterator <student> iter = students.iterator (); iter.hasnext ();) {นักเรียนนักเรียน = (นักเรียน) iter.next (); System.out.println (student.getName ()); -หมายเหตุ: หากคุณต้องการใช้คำหลักที่เลือกคุณต้องใช้นามแฝง ต้องสังเกตอีกจุดหนึ่ง: HQL ไม่รองรับรูปแบบของการเลือก *
/ ** * หากคุณใช้รายการเพื่อสอบถามวัตถุเอนทิตีคำสั่งการสอบถามจะออกเพื่อรับข้อมูลวัตถุเอนทิตี * * ไฮเบอร์เนต: เลือกนักเรียน 0_.id เป็น id0_, student0_.name เป็น name0_, * student0_.createTime เป็น createTime0_, student0_.classesid นักเรียน "). รายการ (); /*Travel*/ for (iterator <student> iter = students.iterator (); iter.hasnext ();) {นักเรียนนักเรียน = (นักเรียน) iter.next (); System.out.println (student.getName ()); -หมายเหตุ: เมื่อใช้. list () เมธอดเพื่อสอบถามวัตถุจะมีการออกคำสั่งเดียวเท่านั้นนั่นคือคำสั่งที่ได้รับข้อมูลวัตถุทางกายภาพ
/*** ปัญหา N+1 จะเกิดขึ้น ที่เรียกว่า N+1 หมายถึงการออกคำสั่ง n+1 SQL * * 1: การออกคำสั่งที่สอบถามรายการ ID * hibernate: เลือกนักเรียน 0_.id เป็น col_0_0_ จาก t_student student0_ * * n: การออกคำสั่ง n: id0_ * student0_.createTime เป็น createTime0_0_, student0_.classesid เป็น classisid0_0_ * จาก t_student student0_ โดยที่ student0_.id =? * */ iterator <student> iter = session.createquery ("จากนักเรียน"). iterate (); /*เดินทาง*/ ในขณะที่ (iter.hasnext ()) {นักเรียนนักเรียน = (นักเรียน) iter.next (); System.out.println (student.getName ()); -หมายเหตุ: เมื่อทำการสืบค้นวัตถุผ่านตัววนซ้ำ () จะมีการออกคำสั่ง n+1 ขั้นแรกจะมีการออกแถลงการณ์เพื่อสอบถามรหัสของวัตถุเอนทิตีจากนั้นคำสั่ง n จะออกตามรหัสที่เกี่ยวข้องกับการสืบค้นวัตถุ n ประสิทธิภาพที่เป็นทางการค่อนข้างแย่
/*จัดเก็บคอลเลกชันแบบสอบถามในแคชระดับแรกเช่นแคชระดับเซสชัน*/ รายการ <student> นักเรียน = เซสชั่นสร้างศูนย์ ("จากนักเรียน") รายการ (); /*transip*/ for (iterator <student> iter = students.iterator (); iter.hasnext ();) {นักเรียนนักเรียน = (นักเรียน) iter.next (); System.out.println (student.getName ()); } system.out.println ("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ การดำเนินการของรายการข้อมูลจะถูกวางไว้ในแคชเซสชัน (แคชระดับแรก) เมื่อใช้ซ้ำ * ก่อนอื่นคำสั่งสอบถามรายการ ID จะออกและจากนั้นข้อมูลที่เกี่ยวข้องจะถูกโหลดในแคชตาม ID แคชสามารถปรับปรุงประสิทธิภาพได้มิฉะนั้นปัญหา N+1 จะเกิดขึ้น**/ iterator <student> iter = session.createquery ("จากนักเรียน"). iterate ();หมายเหตุ: อันที่จริงแล้ว Hibernate ให้แบบสอบถาม Iterator () เพื่อปรับปรุงประสิทธิภาพดังนั้นทำไมจึงช่วยได้มากเกินไป? เหตุผลก็คือ Iterator () ดึงข้อมูลจากแคชระดับแรก หากมีข้อมูลในแคชประสิทธิภาพของมันจะมีประสิทธิภาพค่อนข้างไม่ต้องสงสัยเลย อย่างไรก็ตามเมื่อฉันสอบถามครั้งแรกจะมีข้อมูลในแคชได้อย่างไร สิ่งนี้นำไปสู่ปัญหาที่เรียกว่า N+1 รหัสข้างต้นสามารถหลีกเลี่ยงปัญหา N+1 ความคิดของมันคือการใช้รายการ () ก่อนเพื่อสอบถามเนื่องจากหลังจากรายการ () มีการสืบค้นข้อมูลมีอยู่ในสรุปแคชระดับแรกและเมื่อใช้ iterator () ประสิทธิภาพจะสูงมาก
/*แบบสอบถามตามเงื่อนไข (โดยปกตินามแฝงมักใช้ที่นี่ซึ่งสะดวกกว่า)*/ list <object []> students = session.createquery ("Select S.ID, S.Name จากนักเรียน s ที่ s.name เช่น '%0%'"). รายการ (); /*travel*/ for (iterator <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); -หมายเหตุ: การสืบค้นแบบมีเงื่อนไขเหมือนกับ SQL ดั้งเดิมซึ่งทั้งคู่เป็นที่ที่คำหลัก นอกจากนี้โดยปกติแล้วจะสะดวกกว่าที่จะใช้นามแฝง โปรแกรมข้างต้นคือการสืบค้นหลายแอตทริบิวต์ดังนั้นจึงส่งคืนคอลเลกชันของประเภทอาร์เรย์วัตถุและองค์ประกอบในอาร์เรย์วัตถุเป็นแอตทริบิวต์ที่สอดคล้องกัน
/*การเขียนโปรแกรม chenged*/ list <object []> students = session.createquery ("เลือก S.ID, s.name จากนักเรียน s ที่ s.name ชอบ?") .setParameter (0, "%0%") .List (); /*travel*/ for (iterator <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); -หมายเหตุ: พารามิเตอร์สามารถส่งผ่านตัวยึดตำแหน่งซึ่งสามารถป้องกันการฉีด SQL
/*การเขียนโปรแกรมชิป*/ list <object []> students = session.createquery ("Select S.Id, S.Name จากนักเรียน S ที่ s.name ชอบ: myname") .setParameter ("myname", "%0%") .List (); /*อาร์เรย์วัตถุ*/ สำหรับ (iterator <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); -หมายเหตุ: ชอบ: ไม่มีที่ว่างหลังจากลำไส้ใหญ่ myname มิฉะนั้นจะเกิดข้อผิดพลาด
[java] ดูสำเนาธรรมดา/ * ใช้วิธีการในเมธอดสามารถใช้พารามิเตอร์อย่างเป็นทางการได้เพียงหนึ่งพารามิเตอร์ */ list <object []> students = session.createquery ("Select s.id, s.name จากนักเรียน s ที่ s.id ใน (: ids)") .setParameterList ("ids", วัตถุใหม่ [] /*transip*/ for (iterator <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); -หมายเหตุ: มีพารามิเตอร์อย่างเป็นทางการเพียงอย่างเดียวในวงเล็บหลังจากผ่านไปเมื่อเราตั้งค่าพารามิเตอร์เราสามารถส่งผ่านค่าผ่านอาร์เรย์วัตถุ
/* นักเรียนสอบถามในปี 2009-08 คุณสามารถโทรหาฟังก์ชั่นการจัดรูปแบบวันที่ของ MySQL*/ list <object []> students = session.createquery ("Select S.ID, S.Name จากนักเรียน s โดยที่วันที่ _format (S.Createtime, '%y-%m') =?") /*travel*/ for (iterator <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); - SimpledateFormat SDF = New SimpledateFormat ("YYYY-MM-DD HH: MM: SS"); /*นักเรียนจาก 2009-08-01 ถึง 2009-08-20 สามารถโทรหาฟังก์ชั่นการจัดรูปแบบวันที่ของ MySQL ได้*/ รายการ <Bection []> นักเรียน = เซสชั่น. สร้างสรรค์ ("เลือก S.ID, S.Name จากนักเรียนที่ S.Createtime ระหว่าง? และ?"). sdf.parse ("2009-08-20 23:59:59")) .List (); /*transip*/ for (iterator <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); - / * ใช้ SELECT * คุณต้องใช้คำสั่ง SQL ดั้งเดิมและคล้ายกับ HQL สอบถามคุณสมบัติหลายอย่างดังนั้นจึงส่งคืนคอลเลกชันประเภทอาร์เรย์วัตถุ */ รายการ <วัตถุ []> นักเรียน = เซสชัน CreateSqlQuery ("เลือก * จาก t_student") รายการ (); /*transip*/ for (iterator <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); -หมายเหตุ: HQL ไม่รองรับรูปแบบการสืบค้นของ Select *แต่ Hibernate รองรับคำสั่ง SQL ดั้งเดิม เราสามารถใช้คำสั่ง SQL เพื่อสอบถาม นอกจากนี้ยังคล้ายกับแอตทริบิวต์หลายแอตทริบิวต์ของ HQL ดังนั้นจึงส่งคืนคอลเลกชันของประเภทอาร์เรย์วัตถุ
/*การสืบค้นหน้า, setFirstResult (1) หมายถึงการเริ่มต้นจากข้อมูลแรก; SetMaxResult (2) หมายถึงข้อมูล 2 ชิ้นจะปรากฏขึ้นต่อหน้า*/ รายการนักเรียน = เซสชัน CREATQUERY ("จากนักเรียน") .SetFirStResult (1) .SetMaxResults (2) .List (); /*Travel*/ for (iterator iter = students.iterator (); iter.hasnext ();) {นักเรียนนักเรียน = (นักเรียน) iter.next (); System.out.println (student.getName ()); - /*Query การนำทาง, s.classes.name นำทางจากนักเรียนหนึ่งไปอีกชั้นเรียนในชั้นเรียน (นี่คือการนำทางจากจุดจบไปยังจุดสิ้นสุดที่น้อยลงซึ่งเป็นไปได้ด้วย)*/ รายการ <student> นักเรียน = เซสชัน. createquery ("จากนักเรียนที่ s.classes.name เช่น '%2%'") .List (); /*Travel*/ for (iterator <student> iter = students.iterator (); iter.hasnext ();) {นักเรียนนักเรียน = (นักเรียน) iter.next (); System.out.println (student.getName ()); -หมายเหตุ: s.classes.name ในคำสั่ง Query ข้างต้นคือการได้รับชื่อของชั้นเรียนจากการนำทางของนักเรียนไปยังชั้นเรียน นอกจากนี้คุณยังสามารถนำทางในการย้อนกลับ: นำทางจากชั้นเรียนไปยังนักเรียนในการได้รับแอตทริบิวต์ที่แน่นอน นอกจากนี้คำสั่ง Query ในโปรแกรมหมายถึงการสืบค้นนักเรียนทุกคนที่มี 2 ชื่อในชั้นเรียน
/ *การเชื่อมต่อภายในเพียงใช้คำหลักเข้าร่วม */ list <object []> นักเรียน = session.createquery ("เลือก C.Name, S.Name จากนักเรียนเข้าร่วม S.classes C") .List (); /*ธุรกรรม*/ สำหรับ (ตัววนซ้ำ <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); -หมายเหตุ: คำหลักในการเชื่อมต่อภายในคือการเข้าร่วมและการเชื่อมต่อยังคงดำเนินการโดยใช้นามแฝงและการนำทาง คำแถลงการสืบค้นข้างต้นหมายถึง: สอบถามชื่อชั้นเรียนและชื่อนักเรียนจากตารางนักเรียนและตารางเรียน (การเชื่อมต่อภายในหมายความว่าจะต้องมีคุณสมบัติที่มีค่าในการสอบถามเช่นไม่มีชั้นเรียนหรือไม่มีนักเรียนหรือนักเรียนไม่สามารถสอบถามได้โดยไม่ต้องเรียน)
/*การเข้าร่วมซ้ายใช้คำหลักที่เหลือเข้าร่วม*/ list <object []> students = session.createquery ("เลือก C.Name, S.Name จากนักเรียน S Light เข้าร่วม S.Classes C") .List (); /*transip*/ for (iterator <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); -หมายเหตุ: คำหลักที่ใช้สำหรับการเข้าร่วมด้านซ้ายจะเข้าร่วม คำสั่งค้นหาข้างต้นหมายถึง: จากตารางนักเรียนและชั้นเรียนสอบถามชื่อชั้นเรียนและชื่อนักเรียน เนื่องจากเป็นที่เชื่อมต่อซ้ายนักเรียนที่ไม่มีชั้นเรียนจะถูกสอบถามเช่นกัน
[java] ดูสำเนาธรรมดา/*คีย์เวิร์ดเข้าร่วมขวาถูกต้องเข้าร่วม*/ list <object []> students = session.createquery ("เลือก C.Name, S.Name จากการเข้าร่วมของนักเรียน S.classes C") .List (); /*transip*/ for (iterator <object []> iter = students.iterator (); iter.hasnext ();) {object [] obj = (object []) iter.next (); System.out.println (obj [0] + "," + obj [1]); -หมายเหตุ: คำหลักที่ใช้การเข้าร่วมที่เหมาะสมคือการเข้าร่วมที่ถูกต้อง คำสั่งค้นหาข้างต้นหมายถึง: จากตารางนักเรียนและชั้นเรียนสอบถามชื่อชั้นเรียนและชื่อนักเรียน เนื่องจากเป็นแบบเชื่อมต่อขวาชั้นเรียนที่ไม่มีนักเรียนจะถูกสอบถาม
long count = (ยาว) เซสชั่น createquery ("เลือกจำนวน (*) จากนักเรียน"). uniqueresult ();หมายเหตุ: เฉพาะการสืบค้นทางสถิติเท่านั้นที่สามารถใช้ใน HQL กับ * Uniqueresult () หมายความว่ามีชุดผลลัพธ์เพียงชุดเดียวและประเภทที่ส่งคืนยาว
/*คำสั่งค้นหา*/ string hql = "เลือก c.name, count (s) จากคลาส c เข้าร่วม c.Students กลุ่ม s โดย c.name สั่งซื้อโดย c.name"; รายการ <object []> นักเรียน = session.createquery (HQL) .List (); /*เดินทาง*/ สำหรับ (int i = 0; i <students.size (); i ++) {object [] obj = (วัตถุ []) นักเรียน get (i); System.out.println (obj [0] + "," + obj [1]); -หมายเหตุ: HQL ยังรองรับการจัดกลุ่มการเรียงลำดับ ฯลฯ คำสั่งข้างต้นหมายถึง: สอบถามชื่อของแต่ละชั้นเรียนและสอบถามจำนวนนักเรียนในแต่ละชั้นเรียนกลุ่มตามชื่อคลาสเรียงลำดับตามชื่อคลาส
ข้างต้นคือทั้งหมดที่เกี่ยวกับตัวอย่างรหัสการสืบค้น Hibernate HQL ในบทความนี้ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงหัวข้ออื่น ๆ ที่เกี่ยวข้องในเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!