ตัวดักจับ
เมื่อพูดถึง Interceptor ฉันเชื่อว่ารองเท้าเด็กที่คุ้นเคยกับ Struts2 นั้นคุ้นเคยกับ struts2 อย่างแน่นอน struts2 สามารถปรับแต่งตัวดักเพื่อดำเนินการชุดของงานที่เกี่ยวข้องที่คุณต้องการ และตัวดักจับที่เรากำลังพูดถึงที่นี่ก็มีฟังก์ชั่นที่คล้ายกัน
โดยไม่พูดเรื่องไร้สาระเพียงแค่รหัส:
ต่อไปนี้คือคลาส myinterceptor ซึ่งใช้อินเตอร์เฟส interceptor:
สตริงสาธารณะ onPreprearestatement (String arg0) {return arg0; } บูลีนสาธารณะ onsave (Object arg0, serializable arg1, object [] arg2, string [] arg3, type [] arg4) พ่น callbackexception {ถ้า (arg0 อินสแตนซ์ของผู้ใช้) {system.out.println ("ผู้ใช้จะถูกบันทึก =>"+(ผู้ใช้) } return false; - ฉันจะไม่อ่านวิธีอื่นเพียงแค่ติดตามการใช้งานเริ่มต้น เราต้องเปลี่ยนวิธีการทั้งสองนี้เท่านั้น เราจำเป็นต้องเปลี่ยนค่าส่งคืนในการเตรียมการเพื่อส่งคืนคำสั่ง SQL ปัจจุบัน พารามิเตอร์คือคำสั่ง SQL ที่ดำเนินการผ่านเราสามารถพิมพ์คำสั่งได้โดยส่งคืนโดยตรง
ใน Onsave คุณสามารถบอกได้ว่ามันถูกเรียกเมื่อออม เราสามารถทำงานก่อนการเก็บรักษาล่วงหน้าได้
ฉันเชื่อว่าทุกคนสามารถเข้าใจได้โดยดูชื่อพารามิเตอร์
Serializable หมายถึงพารามิเตอร์ของหมายเลขลำดับซึ่งหมายถึงแอตทริบิวต์ที่แมปกับ ID ฐานข้อมูล
Object [] นี่คือชุดของรัฐซึ่งไม่ได้ใช้มากในช่วงเวลานั้น ฉันจะศึกษาในภายหลัง อย่างไรก็ตาม API อธิบายว่าไม่ว่าค่าในอาร์เรย์นี้จะถูกแก้ไขอย่างไรวิธีการ ONSAVE จะต้องส่งคืนจริง
สตริง [] หมายถึงชื่อของแอตทริบิวต์และประเภท [] คือประเภทของแอตทริบิวต์ที่เกี่ยวข้อง
1) Interceptor นี้สามารถดำเนินการที่สอดคล้องกันก่อนและหลังการบันทึกฐานข้อมูล ตัวอย่างเช่นหากคุณต้องการแก้ไขข้อมูลและเพิ่มคำนำหน้าหรือคำต่อท้ายคุณสามารถใช้มันเพื่อใช้งานได้ ลองดูที่ด้านล่าง
บูลีนสาธารณะ onsave (Object arg0, serializable arg1, object [] arg2, string [] arg3, type [] arg4) พ่น callbackexception {ถ้า (arg0 อินสแตนซ์ของผู้ใช้) {system.out.println ("ผู้ใช้จะถูกบันทึก =>"+(ผู้ใช้) arg0) } // เราเพิ่ม 123 เป็นคำนำหน้าของชื่อที่นี่ผู้ใช้ผู้ใช้ = (ผู้ใช้) arg0; user.setName ("123"+user.getName ()); กลับเท็จ; -มาดูวิธีทดสอบ:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {การกำหนดค่า cfg = การกำหนดค่าใหม่ (). configure (); SessionFactory SessionFactory = cfg.buildsessionFactory (); interceptor interceptor = new myinteceptor (); เซสชั่นเซสชัน = sessionFactory.opensession (interceptor); ผู้ใช้ผู้ใช้ = ผู้ใช้ใหม่ (); user.setName ("Shun"); ธุรกรรม tx = session.beginTransaction (); session.save (ผู้ใช้); tx.commit (); session.close (); - มันง่ายมากเราเพิ่งบันทึกไว้ง่ายๆ ไม่มีไฟล์การแมปและคลาสเอนทิตีที่นี่เพียงแค่ลองใช้
เรียกใช้แล้วเราจะเห็น:
ผู้ใช้ที่จะบันทึก => shun hibernate: แทรกลงในผู้ใช้ (user_name, อายุ) ค่า (?,?) hibernate: อัปเดตผู้ใช้ชุด user_name =?, age =? user_id = ที่ไหน?มันจะอัปเดตชื่อและอายุในตอนท้ายส่วนใหญ่เป็นเพราะเราได้ทำการเปลี่ยนแปลงในวิธี onsave
Public Boolean Onload (Object Arg0, serializable arg1, object [] arg2, string [] arg3, type [] arg4) พ่น callbackexception {ถ้า (arg0 อินสแตนซ์ของผู้ใช้) {system.out.println ("ผู้ใช้จะโหลด =>"+(arg2 [0]+":"+arg2); } ผู้ใช้ user = (ผู้ใช้) arg0; // ตัดสินว่าแอตทริบิวต์ใดเป็นชื่อสำหรับ (int i = 0; i <arg3.length; i ++) {ถ้า (arg3 [i] .equals ("ชื่อ")) {user.setName ((สตริง) arg2 [i]) แทนที่ ("123", "")); arg2 [i] = ((สตริง) arg2 [i]) แทนที่ ("123", ""); }} return false; - ค่าของแอตทริบิวต์ที่แก้ไขเมื่อการโหลดถูกเขียนในวิธี ONLOAD
Arg0 นี่คือวัตถุผู้ใช้ของเรา มันยังไม่มีค่า วิธีนี้เรียกว่าหลังจากวิธีการโหลดดังนั้นจึงไม่มีประโยชน์สำหรับเราที่จะใช้งานผู้ใช้ในเวลานี้และผู้ใช้ชื่อที่นี่คือการดำเนินการที่ไร้ประโยชน์ ส่วนใหญ่ใน:
arg2 [i] = ((สตริง) arg2 [i]) แทนที่ ("123", "");
รหัสนี้จะเปลี่ยนค่าของแอตทริบิวต์ที่ส่งคืนดังนั้นค่าในวัตถุผู้ใช้ที่เราได้รับในโปรแกรมจะเปลี่ยนแปลงเช่นกัน ลองเรียกใช้วิธีทดสอบเพื่อดู:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {การกำหนดค่า cfg = การกำหนดค่าใหม่ (). configure (); SessionFactory SessionFactory = cfg.buildsessionFactory (); interceptor interceptor = new myinteceptor (); เซสชั่นเซสชัน = sessionFactory.opensession (interceptor); ผู้ใช้ผู้ใช้ = (ผู้ใช้) เซสชันการโหลด (user.class, ใหม่ยาว (39)); System.out.println ("ชื่อผู้ใช้:"+user.getName ()); session.close (); -ดูผลลัพธ์เราได้:
Hibernate: เลือก user0_.user_id เป็น user1_0_0_, user0_.user_name เป็น user2_0_0_, user0_.age เป็น Age0_0_ จากผู้ใช้ user0_ โดยที่ user0_.user_id =? ผู้ใช้ที่จะโหลด => 123shun: 0 ชื่อผู้ใช้: ชุน
เราได้ลบ 123 ต้นฉบับและดำเนินการประมวลผลที่เกี่ยวข้องหลังจากการโหลดจริง แต่นี่ไม่ใช่การประมวลผลจริงก่อนการโหลดจริงและเป็นเรื่องน่าสงสัยเล็กน้อยของการเก็งกำไร แต่มันก็เป็นการพิจารณาเช่นกัน Interceptor อาจถูกใช้มากที่สุดในการประมวลผลที่เกี่ยวข้องของบันทึก ตัวอย่างเช่นเราจำเป็นต้องบันทึกตามลำดับสำหรับการดำเนินการแต่ละครั้งดังนั้น Interceptor จึงเป็นตัวเลือกที่ดี
ของสะสม
จำไว้ว่าชุดที่เราใช้ในตัวอย่างก่อนหน้านี้คุณยังคงมีความประทับใจหรือไม่? หากคุณไม่ได้ไปตรวจสอบข้อมูลและตรวจสอบ วันนี้เราจะเรียนรู้เกี่ยวกับคอลเลกชันเหล่านี้
มาถึงจุด
1) ก่อนอื่นมาเรียนรู้ชุด ทุกคนรู้ว่ามีชุดในแพ็คเกจ Java Util ดังนั้นความแตกต่างและการเชื่อมต่อระหว่างชุดและตั้งค่าในไฮเบอร์เนตคืออะไร? เราเปิด Hibernate API ค้นหาชุดและคุณสามารถดูได้
สิ่งที่เราเห็นคือคลาสหลักของคอลเลกชันไฮเบอร์เนต มันเป็นคลาสนามธรรมที่มีชุดของคลาสการใช้งานคอนกรีต เมื่อเรายังคงเห็นวิธีการต่อไปนี้เราพบว่าคลาสนี้ใช้การห่อหุ้มของคอลเลกชัน Java ดังนั้นเราจึงเข้าใจว่าชุดไฮเบอร์เนตที่เรียกว่าจริง ๆ แล้วจะห่อหุ้มชุด Java เท่านั้น
ดังนั้นลักษณะนี้ที่ไม่อนุญาตให้มีองค์ประกอบที่ซ้ำกันในชุดในไฮเบอร์เนตหรือไม่? คำตอบคือแน่นอนใช่
เราไม่ได้ดูที่นี่ ในอดีตเมื่อเราเรียนรู้การทำแผนที่เราเชื่อมโยงคุณสมบัติโดยตรงกับชั้นเรียนที่เกี่ยวข้อง แต่วันนี้เราไม่ได้เป็นเช่นนี้ เราใช้วิธีอื่นเพียงแค่เชื่อมโยงสตริงเพื่อดูว่ามีปัญหาใด ๆ หรือไม่
แต่ก่อนที่จะดูคำถามนี้มาดูการเปรียบเทียบสตริงใน Java
สิ่งที่เราเห็นคือคลาสหลักของคอลเลกชันไฮเบอร์เนต มันเป็นคลาสนามธรรมที่มีชุดของคลาสการใช้งานคอนกรีต เมื่อเรายังคงเห็นวิธีการต่อไปนี้เราพบว่าคลาสนี้ใช้การห่อหุ้มของคอลเลกชัน Java ดังนั้นเราจึงเข้าใจว่าชุดไฮเบอร์เนตที่เรียกว่าจริง ๆ แล้วจะห่อหุ้มชุด Java เท่านั้น
ดังนั้นลักษณะนี้ที่ไม่อนุญาตให้มีองค์ประกอบที่ซ้ำกันในชุดในไฮเบอร์เนตหรือไม่? คำตอบคือแน่นอนใช่
เราไม่ได้ดูที่นี่ ในอดีตเมื่อเราเรียนรู้การทำแผนที่เราเชื่อมโยงคุณสมบัติโดยตรงกับชั้นเรียนที่เกี่ยวข้อง แต่วันนี้เราไม่ได้เป็นเช่นนี้ เราใช้วิธีอื่นเพียงแค่เชื่อมโยงสตริงเพื่อดูว่ามีปัญหาใด ๆ หรือไม่
แต่ก่อนที่จะดูคำถามนี้มาดูการเปรียบเทียบสตริงใน Java
โมฆะคงที่สาธารณะหลัก (String [] args) {String S1 = "Shun1"; สตริง s2 = "shun1"; System.out.println ("S1 == S2:"+(S1 == S2)); - ฉันเชื่อว่ารองเท้าเด็กหลายคนรู้ว่าคำตอบนั้นเป็นจริง
ก่อนที่จะทำตัวอย่างลองมาดูไฟล์การแมปของเรา เราจะไม่เขียนคลาสการทำแผนที่:
นี่คือไฟล์การแมปสำหรับ TUSER:
<class name = "tuser" table = "t_user" dynamic-insert = "true" dynamic-update = "true" dynamic-update = "true"> <id name = "id" คอลัมน์ = "id"> <generator/> </id> <property name = "ชื่อ" type = "java.lang.string" column = "age"/> <set name = "ที่อยู่" cascade = "all" table = "t_address"> <คีย์คอลัมน์ = "user_id"/> <!-<แบบหนึ่งต่อหลาย/>-> <element column = "address" type = "string"/> </set>
ถัดไปคือไฟล์การแมปที่อยู่:
<class name = "address" table = "t_address" dynamic-insert = "false" dynamic-update = "false"> <id name = "id" คอลัมน์ = "id" type = "java.lang.integer"> <generator /> < /id> not-null = "true"> </multy-to-one> </class>
รองเท้าเด็กเห็นได้ชัดเจน ฉันแสดงความคิดเห็นแบบหนึ่งถึงหลายคนในชุดใน TUSER และองค์ประกอบที่ใช้ ไม่ว่าปัญหาคืออะไรลองดูที่ฐานข้อมูลก่อน:
นี่คือตาราง t_address:
นี่คือตาราง t_user:
เราสามารถเห็นผู้ใช้ที่มี ID 4 สอดคล้องกับที่อยู่สามแห่ง ถัดไปมาดูวิธีทดสอบ:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {การกำหนดค่า cfg = การกำหนดค่าใหม่ (). configure (); SessionFactory SessionFactory = cfg.buildsessionFactory (); เซสชัน = sessionfactory.opensession (); tuser user = (tuser) เซสชันโหลด (tuser.class, จำนวนเต็มใหม่ (4)); set set = user.getAddresses (); session.close (); System.out.println ("ขนาดที่อยู่:"+set.size ()); - คลาสการสืบค้นที่ง่ายมากเพิ่งหยิบผลลัพธ์นี้ออกมาเราเห็นปรากฏการณ์แปลก ๆ :
ขนาดที่อยู่: 1
นี่คือผลลัพธ์!
คุณจะบอกว่ามันต้องผิดมันเป็นข้อผิดพลาดในไฮเบอร์เนต ฉันต้องมีความสุขที่นี่ ในที่สุดฉันก็สามารถส่งข้อผิดพลาดได้ เมื่อฉันเปลี่ยนงานฉันสามารถพูดได้ว่าฉันส่งข้อผิดพลาดสำหรับไฮเบอร์เนต ฮ่าฮ่า แต่น่าเสียดายที่นี่ไม่ใช่ข้อผิดพลาด
ฉันเพิ่งบอกว่าการเปรียบเทียบสายที่เรามีอยู่ข้างหน้าคือการปูทางที่นี่ดังนั้นจะปูได้อย่างไร?
เราใช้ SET ในไฟล์กำหนดค่าและเชื่อมโยงผ่านอักขระสตริง จากนั้นเมื่อมันถูกนำออกไปในฐานข้อมูลและใส่ลงในชุดมันจะพิจารณาก่อนว่าค่าของอักขระที่เกี่ยวข้องมีค่าเท่ากันหรือไม่ ที่นี่เนื่องจากค่าของเราเท่ากัน (เราจะไม่ขุดว่ามันเปรียบเทียบอย่างไรในขณะนี้) เราจำเป็นต้องรู้ว่าเมื่อเราใช้สตริงเพื่อเปรียบเทียบเราจะตกอยู่ในกับดักสตริงในชวาอีกครั้ง หากคุณพบว่ามีเพียงหนึ่งเดียวการลบจะเป็นปัญหามากขึ้นเมื่อลบออกมันจะลบบันทึกเดียวกันทั้งหมด
แล้วมาดูที่ที่ถูกลบ:
tuser user = (tuser) เซสชันโหลด (tuser.class, จำนวนเต็มใหม่ (4)); ธุรกรรม tx = session.beginTransaction (); Object obj = user.getAddresses (). iterator (). next (); user.getAddresses (). ลบ (obj); tx.commit (); session.close ();
คำสั่งเอาท์พุทโดยไฮเบอร์เนตที่นี่คือ:
ไฮเบอร์เนต: ลบจาก t_address โดยที่ user_id =?
ฉันเชื่อว่าทุกคนรู้ว่าเมื่อใดที่จะลบที่อยู่ทั้งหมดภายใต้ผู้ใช้ ไม่มีทางเลือกนอกจากต้องลบทั้งหมดนี้
ดังนั้นคุณต้องให้ความสนใจกับมันในการพัฒนาจริง
2) เราพูดคุยเกี่ยวกับชุดข้างต้นดูเหมือนว่ามันจะไม่เป็นที่น่าพอใจมาก มีกับดักเช่นนี้ แต่ไม่มีทาง ชุดเป็นสิ่งที่เราใช้มากที่สุดและโดยทั่วไปจะไม่มีใครเชื่อมโยงสตริงโดยตรง แต่หลายคนยังคงไม่มีความสุขดังนั้น Hibernate จะมีกระเป๋าพิเศษตามที่ต้องการ (อาจจะไม่เป็นไปตามที่ต้องการบางทีบางคนในพวกเขาไม่พอใจฮ่าฮ่า)
ก่อนอื่นดูการใช้งานขั้นพื้นฐาน:
ก่อนอื่นเราต้องแก้ไขแท็กชุดในไฟล์การแมป TUSER ก่อนหน้าเป็น:
<bag name = "ที่อยู่" lazy = "true" table = "t_address"> <คีย์คอลัมน์ = "user_id" /> <องค์ประกอบประเภท = "สตริง" คอลัมน์ = "ที่อยู่" /> </ag>
และคลาสเอนทิตีที่สอดคล้องกันจำเป็นต้องแก้ไขประเภทที่อยู่เป็นประเภทรายการ
ที่นี่เราเพิ่มสามที่อยู่:
เราเรียกใช้รหัสทดสอบ:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {การกำหนดค่า cfg = การกำหนดค่าใหม่ (). configure (); SessionFactory SessionFactory = cfg.buildsessionFactory (); เซสชัน = sessionfactory.opensession (); tuser user = (tuser) เซสชันโหลด (tuser.class, จำนวนเต็มใหม่ (4)); System.out.println ("ขนาดที่อยู่:"+user.getAddresses (). size ()); session.close (); -
ที่นี่เราเห็น:
ขนาดที่อยู่: 3
เวลานี้เราสามารถเห็นได้ทั้งหมดไม่ว่าจะมีการทำซ้ำหรือไม่ก็ตาม
แต่เราเพิ่งดูปัญหาการลบ กระเป๋ายังไม่ได้รับการแก้ไขที่นี่และเราจำเป็นต้องใช้ idbag เราเห็นไฟล์การกำหนดค่าและต้องการการแก้ไขต่อไปนี้:
idbag name = "addresses" table = "t_address" lazy = "true"> <collection-id type = "int" คอลัมน์ = "id"> <generator /> < /collection-id> <คีย์คอลัมน์ = "user_id" />
เราเห็นว่ามันมีคอลเลกชันมากกว่าหนึ่งรายการมากกว่ากระเป๋าเพื่อระบุหมายเลขบันทึกที่จะลบ
เมื่อเราเรียกใช้รหัสที่ถูกลบอีกครั้ง:
tuser user = (tuser) เซสชันโหลด (tuser.class, จำนวนเต็มใหม่ (4)); ธุรกรรม tx = session.beginTransaction (); Object obj = user.getAddresses (). iterator (). next (); user.getAddresses (). ลบ (obj); tx.commit ();
เราเห็นว่าคำสั่งเอาต์พุตคือ:
Hibernate: ลบจาก t_address โดยที่ id =?
เวลานี้มันจะไม่ถูกลบผ่าน user_id แต่ขึ้นอยู่กับ ID ของ t_address ซึ่งหมายความว่ามันจะลบบันทึกที่เราต้องลบ
เราเห็นฐานข้อมูลและบันทึกอยู่ในขณะนี้:
เราได้ลบระเบียนแรกที่ถูกต้อง
3) หลังจากดูสองวิธีข้างต้นลองมาดูแผนที่ ความแตกต่างที่ใหญ่ที่สุดระหว่างมันกับสองข้างต้นคือมันสามารถสอดคล้องกับค่าคีย์ ดูโดยตรงที่รหัสมุมมองที่ใช้งานง่าย:
ก่อนอื่นเราต้องแก้ไขไฟล์การกำหนดค่า:
<map name = "addresses" table = "t_address" lazy = "true"> <คีย์คอลัมน์ = "user_id" /> <index type = "string" คอลัมน์ = "type" /> <องค์ประกอบประเภท = "สตริง" คอลัมน์ = "ที่อยู่" /> < /map>
ความแตกต่างที่ใหญ่ที่สุดระหว่างมันกับสองก่อนหน้าคือมีดัชนีซึ่งเทียบเท่ากับคีย์แผนที่ใน Java และเราใช้สิ่งนี้เพื่อดึงบันทึกที่เกี่ยวข้อง โปรดจำไว้ว่าหลังจากเปลี่ยนที่นี่คุณต้องเปลี่ยนคลาสเอนทิตีที่เกี่ยวข้องและคุณต้องเปลี่ยนประเภทของแอตทริบิวต์ที่อยู่เป็นแผนที่
ดูข้อมูลฐานข้อมูล:
ที่นี่เราเห็นว่ามีสำนักงานสองแห่งและบ้านหนึ่งหลังดังนั้นควรใช้สำนักงานใด
ไม่ต้องกังวลเราจะรู้หลังจากเรียกใช้รหัสทดสอบ:
tuser user = (tuser) เซสชันโหลด (tuser.class, จำนวนเต็มใหม่ (4)); System.out.println (user.getAddresses (). รับ ("home")); System.out.println (user.getAddresses (). รับ ("Office"));Shanwei Shanghai
ใช่ตามที่แสดงให้เห็นว่าเราได้รับสิ่งที่อยู่เบื้องหลังซึ่งเหมือนกับหลักการของแผนที่ ค่าที่เก็บไว้จะเขียนทับค่าก่อนหน้า (หากเป็นคีย์เดียวกัน)
แผนที่ค่อนข้างง่ายซึ่งเปรียบได้กับสองคนแรก
4) มาดูอันสุดท้าย รายการแตกต่างจากรายการก่อนหน้านี้และสามารถจัดเรียงได้
ลองมาดูกันว่ามันถูกนำไปใช้อย่างไร:
ก่อนอื่นให้แก้ไขไฟล์การแมป:
<list name = "ที่อยู่" table = "t_address" lazy = "true"> <คีย์คอลัมน์ = "user_id" /> <index type = "string" คอลัมน์ = "idx" /> <องค์ประกอบประเภท = "สตริง" คอลัมน์ = "ที่อยู่"
มันคล้ายกับการกำหนดค่าของแผนที่ แต่แอตทริบิวต์ของดัชนีแตกต่างกัน ดัชนีในแผนที่ใช้เป็นคีย์เพื่อรับค่าในขณะที่ดัชนีของรายการใช้เป็นการเรียงลำดับ
มาดูฐานข้อมูล:
เราตั้งค่าสามค่าตามลำดับ 0, 1 และ 2
ลองเรียกใช้รหัสเพื่อเปลี่ยนค่า 0 และ 2:
tuser user = (tuser) เซสชันโหลด (tuser.class, จำนวนเต็มใหม่ (4)); ธุรกรรม tx = session.beginTransaction (); Object obj1 = user.getAddresses (). รับ (0); Object obj2 = user.getAddresses (). รับ (2); user.getAddresses (). set (0, obj2); user.getAddresses (). set (2, obj1); tx.commit ();
เราเห็นผลลัพธ์:
เราเห็นว่า 0 และ 2 ถูกแทนที่และแน่นอนว่านี่เป็นเพียงการเปลี่ยนค่าของ IDX แต่สิ่งนี้ได้ใช้ฟังก์ชันการเรียงลำดับโดยทั่วไป