มันใช้ Spring Data JPA มาระยะหนึ่งแล้ว ในช่วงเวลานี้ฉันได้เรียนรู้บางสิ่งและพบปัญหาบางอย่าง ฉันจะแบ่งปันกับคุณที่นี่
คำนำ:
ข้อมูลเบื้องต้นเกี่ยวกับข้อมูลฤดูใบไม้ผลิ:
Spring Data เป็นเฟรมเวิร์กโอเพ่นซอร์สสำหรับการทำให้การเข้าถึงฐานข้อมูลง่ายขึ้นและรองรับบริการคลาวด์ เป้าหมายหลักของมันคือการเข้าถึงข้อมูลที่สะดวกและรวดเร็วและเพื่อรองรับกรอบการลดแผนที่และบริการข้อมูลคลาวด์คอมพิวติ้ง ข้อมูลฤดูใบไม้ผลิมีโครงการย่อยหลายโครงการ:
Commons - จัดเตรียมกรอบพื้นฐานที่ใช้ร่วมกันที่เหมาะสมสำหรับใช้ในแต่ละโครงการย่อยและรองรับการคงอยู่ข้ามตาราง
JPA - ลดความสามารถในการสร้างระดับการเข้าถึงข้อมูล JPA และระดับการคงอยู่ในพื้นที่เก็บข้อมูล
Hadoop - งาน MapReduce ตามการกำหนดค่างาน Hadoop ของฤดูใบไม้ผลิและรูปแบบการเขียนโปรแกรม POJO
Key -Value - รวม Redis และ Riak เพื่อจัดหาบรรจุภัณฑ์ที่เรียบง่ายในหลาย ๆ สถานการณ์ทั่วไป
เอกสาร - รวมฐานข้อมูลเอกสาร: CouchDB และ MongoDB และให้การแมปการกำหนดค่าพื้นฐานและการสนับสนุนห้องสมุด
กราฟ - รวม Neo4J เพื่อจัดทำโมเดลการเขียนโปรแกรมที่ใช้ POJO ที่ทรงพลัง
กราฟ Roo Addon - สนับสนุน ROO สำหรับ neo4j
ส่วนขยาย JDBC - รองรับ Oracle Rad, คิวขั้นสูงและประเภทข้อมูลขั้นสูง
การแมป - ให้กรอบการทำแผนที่วัตถุตาม Grails รองรับฐานข้อมูลที่แตกต่างกัน
ตัวอย่าง - โปรแกรมตัวอย่างเอกสารและฐานข้อมูลกราฟ
คำแนะนำ - เอกสารขั้นสูง
1. บทนำสู่สปริงข้อมูล JPA
Spring Data JPA เป็นเฟรมเวิร์กแอปพลิเคชัน JPA ที่ถูกห่อหุ้มด้วยสปริงตามข้อกำหนดของ ORM Framework และ JPA และจัดทำชุดโซลูชันเลเยอร์การเข้าถึงข้อมูลที่สมบูรณ์
2. ฟังก์ชั่นสปริงข้อมูล JPA
Spring Data JPA มีฟังก์ชั่นที่ทรงพลังมาก ที่นี่เราข้ามขั้นตอนการก่อสร้างสิ่งแวดล้อมและดู "ความหวาน" ของข้อมูลฤดูใบไม้ผลิ JPA
Spring Data JPA ให้ผู้ใช้กับอินเทอร์เฟซต่อไปนี้:
3. สปริงข้อมูล JPA อินเตอร์เฟส
1. อินเทอร์เฟซ crudrepository
สร้างคลาสเอนทิตี:
@ENTITY @Table (name = "user") ผู้ใช้คลาสสาธารณะ {@id @IneratedValue ID จำนวนเต็มส่วนตัว; // บัญชีสตริงส่วนตัวบัญชี; // ชื่อชื่อสตริงส่วนตัว; // รหัสผ่านรหัสผ่านสตริงส่วนตัว; // อีเมลสตริงส่วนตัว - เขียนอินเทอร์เฟซและสืบทอดอินเตอร์เฟส crudrepository:
ส่วนต่อประสานสาธารณะ userrepository ขยาย crudrepository <ผู้ใช้, จำนวนเต็ม> {} เขียนคลาสทดสอบ (เพื่อดูเอฟเฟกต์มากขึ้นคลาสทดสอบทั้งหมดไม่ได้ใช้การยืนยันและข้อความพิมพ์ที่ใช้โดยตรง):
ชั้นเรียนสาธารณะ userrepositorytest {@autowired ส่วนตัว userrepository dao; @test // บันทึกโมฆะสาธารณะ testsave () {ผู้ใช้ผู้ใช้ = ผู้ใช้ใหม่ (); user.setName ("chhliu"); user.setAccount ("10,000"); user.setEmail ("[email protected]"); user.setPassword ("123456"); dao.save (ผู้ใช้); } @test // บันทึกโมฆะสาธารณะ testsave1 () {list <ผู้ใช้> users = new ArrayList <user> (); ผู้ใช้ผู้ใช้ = ผู้ใช้ใหม่ (); user.setName ("tanjie"); user.setAccount ("10,000"); user.setEmail ("[email protected]"); user.setPassword ("123456"); users.add (ผู้ใช้); ผู้ใช้ = ผู้ใช้ใหม่ (); user.setName ("Esdong"); user.setAccount ("10,000"); user.setEmail ("[email protected]"); user.setPassword ("123456"); users.add (ผู้ใช้); ผู้ใช้ = ผู้ใช้ใหม่ (); user.setName ("qinhongfei"); user.setAccount ("10,000"); user.setEmail ("[email protected]"); user.setPassword ("123456"); users.add (ผู้ใช้); ผู้ใช้ = ผู้ใช้ใหม่ (); user.setName ("Huizhang"); user.setAccount ("10,000"); user.setEmail ("[email protected]"); user.setPassword ("123456"); users.add (ผู้ใช้); ผู้ใช้ = ผู้ใช้ใหม่ (); user.setName ("Caican"); user.setAccount ("10,000"); user.setEmail ("[email protected]"); user.setPassword ("123456"); users.add (ผู้ใช้); dao.save (ผู้ใช้); } @test // อัปเดตโมฆะสาธารณะ testupDate () {ผู้ใช้ผู้ใช้ = dao.findone (1); user.setPassword ("123890"); // ในการใช้ฟังก์ชั่นการอัปเดตด้วยวิธีนี้คุณต้องเพิ่ม @Transaction สิ่งที่คำอธิบายประกอบเข้ากับเลเยอร์บริการ} @test // ลบโมฆะสาธารณะ testDelete () {dao.delete (2); } @Test // Query เป็นโมฆะสาธารณะทั้งหมด testFindall () {list <ผู้ใช้> users = (รายการ <user>) dao.findall (); System.out.println (json.tojsonstring (ผู้ใช้)); } @Test // Query ว่าวัตถุ ID ที่ระบุนั้นมีอยู่ในโมฆะ Public Testisexist () {บูลีน isExist = dao.exists (8); System.out.println (isexist); } @Test // Query Public Void TestFinduserByIds () {list <integer> listIds = new ArrayList <integer> (); listids.add (2); listids.add (4); listids.add (7); รายการ <user> users = (รายการ <user>) dao.findall (listids); System.out.println (json.tojsonstring (ผู้ใช้)); - อย่างที่คุณเห็น ณ จุดนี้ฉันเขียนเพียงคลาสอินเตอร์เฟสหนึ่งคลาสและไม่ได้ใช้คลาสอินเตอร์เฟสนี้ดังนั้นฉันจึงสามารถดำเนินการ CRUD ขั้นพื้นฐานให้เสร็จสมบูรณ์ เนื่องจากอินเทอร์เฟซนี้จะสร้างวิธีการโดยอัตโนมัติสำหรับการเพิ่มลบการแก้ไขและค้นหาวัตถุโดเมนเพื่อใช้โดยตรงจากเลเยอร์ธุรกิจ
อินเทอร์เฟซถูกกำหนดดังนี้และมีวิธีการทั้งหมด 11 วิธีซึ่งโดยทั่วไปสามารถตอบสนองการดำเนินการ CRUD อย่างง่ายและการดำเนินการแบทช์:
@NorePositoryBean อินเตอร์เฟสสาธารณะ crudrepository <t, id ขยาย serializable> ขยายที่เก็บ <t, id> {<s ขยาย t> s บันทึก (เอนทิตี); // บันทึก <s ขยาย t> iterable <s> บันทึก วัตถุมี iterable <t> findall (); // การสืบค้นวัตถุทั้งหมด iteRable <t> findall (iterable <id> ids); // การสืบค้นวัตถุทั้งหมดตามรายการ id รายการยาว (); // คำนวณจำนวนทั้งหมดของวัตถุ void delete (id id); ลบโมฆะ deleteAll (); // ลบทั้งหมด} 2. PagingandsortingRepository Interface
ส่วนต่อประสาน PagingandsortingRepository สืบทอดอินเตอร์เฟส crudrepository
เขียนอินเทอร์เฟซและสืบทอดอินเทอร์เฟซ
อินเทอร์เฟซสาธารณะ userrepositoryWithOrder ขยาย pagingandsortingRepository <ผู้ใช้จำนวนเต็ม> {} เขียนคลาสทดสอบ:
@runwith (springjunit4classrunner.class) @contextconfiguration (locations = {"classpath: applicationcontext-config.xml"}) @transactionConfiguration (defaultrollback = false) @Test Public Void TestOrder () {sort sort = new sort (direction.desc, "id"); PAGABLE PAGABLE = NEW PAGEREQUEST (0, 5, เรียงลำดับ); หน้า <ผู้ใช้> หน้า = dao.findall (pageable); System.out.println (json.tojsonstring (หน้า)); System.out.println (page.getSize ()); - ตราบใดที่คุณสืบทอดอินเทอร์เฟซนี้ Spring Data JPA จะให้ฟังก์ชั่นของการปนเปื้อนและการเรียงลำดับแก่คุณแล้ว อินเทอร์เฟซถูกกำหนดดังนี้และมีสองวิธีสำหรับการใช้งานโดยที่ t คือคลาสเอนทิตีที่จะดำเนินการและ id เป็นประเภทของคีย์หลักคลาสเอนทิตีคลาส
@NorePositoryBean อินเตอร์เฟสสาธารณะ pagingandsortingRepository <t, id ขยาย serializable> ขยาย crudrepository <t, id> {iterable <t> findall (เรียงลำดับ); 3. อินเตอร์เฟส JParePository
หากธุรกิจจำเป็นต้องจัดให้มีการดำเนินงาน CRUD และยังมีฟังก์ชั่นการเพจและการเรียงลำดับคุณสามารถสืบทอดอินเทอร์เฟซนี้ได้โดยตรง อินเทอร์เฟซนี้สืบทอดส่วนต่อประสาน PagingandsortingRepository
อินเทอร์เฟซถูกกำหนดดังนี้:
ส่วนต่อประสานสาธารณะ jparepository <t, id ขยาย serializable> ขยาย pagingandsortingRepository <t, id> {list <t> findall (); // query วัตถุทั้งหมดอย่าเรียงลำดับรายการ <t> findall (เรียงลำดับ); ซิงโครไนซ์กับฐานข้อมูล t SaveAndFlush (t entity); // บันทึกและบังคับให้ซิงโครไนซ์เป็นโมฆะ deleteInbatch (iterable <t> เอนทิตี); // batch ลบ void deleteallinBatch (); // ลบทั้งหมด}} 4. JPASPECIFICATION EXCUTOR อินเตอร์เฟส
อินเทอร์เฟซนี้ให้การสนับสนุนการสืบค้นเกณฑ์ JPA โปรดทราบว่าอินเทอร์เฟซนี้มีความพิเศษมากและไม่ได้อยู่ในระบบที่เก็บ Spring Data JPA จะไม่สแกนและรับรู้โดยอัตโนมัติดังนั้นจะไม่พบถั่วที่สอดคล้องกัน เราจำเป็นต้องสืบทอดอินเตอร์เฟซย่อยใด ๆ ที่สืบทอดที่เก็บหรือสืบทอดอินเตอร์เฟสที่เก็บโดยตรง Spring Data JPA จะสแกนและรับรู้และดำเนินการจัดการแบบครบวงจรโดยอัตโนมัติ
อินเทอร์เฟซเขียนดังนี้:
ข้อมูลจำเพาะส่วนต่อประสานสาธารณะ ExecutorRepository ขยาย crudrepository <ผู้ใช้, จำนวนเต็ม>, jpaspecificationExecutor <user> {} คลาสบริการ:
@Service ข้อมูลจำเพาะระดับสาธารณะ / *** คำอธิบาย: สอบถามผู้ใช้ตามชื่อ*/ ผู้ใช้สาธารณะ findUserByName (ชื่อสตริงสุดท้าย) {return dao.findone (ข้อกำหนดใหม่ <ผู้ใช้> () {@Override สาธารณะ predicate toPredicate (รูท <ผู้ใช้> รูท, criteriaQuery <? - } / *** คำอธิบาย: สอบถามผู้ใช้ตามชื่อและอีเมล* / ผู้ใช้สาธารณะ FindUserBynameandEmail (ชื่อสตริงสุดท้าย, อีเมลสตริงสุดท้าย) {return dao.findone (ข้อมูลจำเพาะใหม่ <user> () {@Override สาธารณะ ArrayList <Predicate> (); cb.and (list.toarray (p));}}); } / *** คำอธิบาย: การสืบค้นแบบรวม* / ผู้ใช้สาธารณะ FinduserByUser (ผู้ใช้ขั้นสุดท้าย uservo) {return dao.findone (ข้อมูลจำเพาะใหม่ <suser> () {@Override สาธารณะ predicate toPredicate (รูท <ผู้ใช้> รูท, เกณฑ์ <?> query, criteriabuilder uservo.getName ()); cb.and (predicate, cb.equal (root.get ("อีเมล"), uservo.getpassword ()); } / *** คำอธิบาย: ช่วงการสืบค้นในวิธีการเช่นการสอบถามผู้ใช้ด้วย ID ผู้ใช้ใน [2,10]* / รายการสาธารณะ <ผู้ใช้> findUserByIds (รายการสุดท้าย <integer> ids) {return dao.findall (ข้อมูลจำเพาะใหม่ <ผู้ใช้> () root.in (ids);}}); } / *** คำอธิบาย: Range Query Method Method เช่นการสอบถามผู้ใช้ทั้งหมดที่มี ID ผู้ใช้มากกว่า 9* / รายการสาธารณะ <ผู้ใช้> FindUserByGTID (ID int สุดท้าย) {return dao.findall (ข้อมูลจำเพาะใหม่ <user> () cb.gt (root.get ("id"). เป็น (integer.class), id);}}); } / *** คำอธิบาย: Range Query LT วิธีการเช่นการสอบถามผู้ใช้ที่มีรหัสผู้ใช้น้อยกว่า 10* / รายการสาธารณะ <ผู้ใช้> findUserBylTid (ID int สุดท้าย) {return dao.findall (ข้อมูลจำเพาะใหม่ <user> () {@Override Publicer Predicate cb.lt (root.get ("id"). เป็น (integer.class), id);}}); } / *** คำอธิบาย: ช่วงการสืบค้นระหว่างวิธีการเช่นการสืบค้นผู้ใช้ที่มี ID ระหว่าง 3 และ 10* / รายการสาธารณะ <user> findUserBetweenid (เริ่มสุดท้าย int เริ่มสุดท้าย int สุดท้าย) {return dao.findall (สเปคใหม่ <user> () {@override) cb.between (root.get ("id"). เป็น (integer.class), start, end); } / *** คำอธิบาย: การเรียงลำดับและการดำเนินการ pagination* / หน้าสาธารณะ <user> findUserAndOrder (ID int สุดท้าย) {sort sort = การเรียงลำดับใหม่ (direction.desc, "id"); ส่งคืน dao.findall (ข้อมูลจำเพาะใหม่ <user> () {@Override Public Prevent Predicate topredicate (รูท <ผู้ใช้> รูท, เกณฑ์ <?> แบบสอบถาม, เกณฑ์ CB) {ส่งคืน cb.gt (root.get ("id") } / *** คำอธิบาย: เฉพาะการดำเนินการเรียงลำดับ* / รายการสาธารณะ <ผู้ใช้> findUserAndordERSecondMethod (ID int สุดท้าย) {return dao.findall (ข้อมูลจำเพาะใหม่ <user> () {@Override สาธารณะ cb.gt (root.get ("id"). เป็น (integer.class), id); - คลาสทดสอบ:
@runwith (springjunit4classrunner.class) @contextconfiguration (ตำแหน่ง = {"classpath: applicationcontext-config.xml"}) @transactionConfiguration (defaultrollback = false) @transactional คลาสสาธารณะ @Test โมฆะสาธารณะ Public TestFinduserByName () {ผู้ใช้ผู้ใช้ = manager.finduserByName ("chhliu"); System.out.println (json.tojsonstring (ผู้ใช้)); } @Test โมฆะสาธารณะ TestFinduserByNameAndEmail () {ผู้ใช้ผู้ใช้ = manager.finduserBynameAndemail ("chhliu", "chhliu @.com"); System.out.println (json.tojsonstring (ผู้ใช้)); } @Test โมฆะสาธารณะ TestFinduserByUservo () {ผู้ใช้ผู้ใช้ = ผู้ใช้ใหม่ (); user.setName ("chhliu"); user.setEmail ("[email protected]"); ผู้ใช้ u = manager.finduserbyuser (ผู้ใช้); System.out.println (json.tojsonstring (u)); } @Test โมฆะสาธารณะ testFinduserByIds () {รายการ <ผู้ใช้> ผู้ใช้ = manager.finduserByIds (arrayList ใหม่ <Integer> (array.aslist (1,3,5,6))); System.out.println (json.tojsonstring (ผู้ใช้)); } @Test โมฆะสาธารณะ testFinduserByGTID () {รายการ <ผู้ใช้> ผู้ใช้ = manager.finduserByGTID (5); System.out.println (json.tojsonstring (ผู้ใช้)); } @Test โมฆะสาธารณะ TestFinduserBylTid () {รายการ <ผู้ใช้> ผู้ใช้ = manager.finduserBylTid (5); System.out.println (json.tojsonstring (ผู้ใช้)); } @Test โมฆะสาธารณะ testFinduserBetweenid () {รายการ <ผู้ใช้> ผู้ใช้ = manager.finduserBetweenid (4, 9); System.out.println (json.tojsonstring (ผู้ใช้)); } @Test โมฆะสาธารณะ TestFindUNANDORDERDORDERDORDERDERNED () {หน้า <ผู้ใช้> ผู้ใช้ = manager.finduserAndOrder (1); System.out.println (json.tojsonstring (ผู้ใช้)); } @Test โมฆะสาธารณะ TestFindUNANDORDERSECONDMETHOD () {LIST <Somer> ผู้ใช้ = Manager.FINDUNANDORDERSECONDMETHOD (1); System.out.println (json.tojsonstring (ผู้ใช้)); - 5. ส่วนต่อประสานที่เก็บ
อินเทอร์เฟซนี้เป็นอินเทอร์เฟซพื้นฐานที่สุดมันเป็นเพียงอินเทอร์เฟซที่เป็นสัญลักษณ์และไม่มีการกำหนดวิธีการดังนั้นการใช้อินเทอร์เฟซนี้คืออะไร? เนื่องจาก Spring Data JPA ให้อินเทอร์เฟซนี้แน่นอนว่ามีประโยชน์ ตัวอย่างเช่นบางวิธีที่เราไม่ต้องการให้ภายนอก ตัวอย่างเช่นเราต้องการให้วิธีการเพิ่มเติมและการแก้ไขและไม่ใช่วิธีการลบจากนั้นอินเทอร์เฟซก่อนหน้านี้ไม่สามารถทำได้ ในเวลานี้เราสามารถสืบทอดอินเทอร์เฟซนี้และคัดลอกวิธีการที่เกี่ยวข้องในอินเทอร์เฟซ crudrepository ไปยังอินเตอร์เฟสที่เก็บ
สรุป: นักพัฒนาควรเลือกห้าอินเทอร์เฟซข้างต้นอย่างไร ในความเป็นจริงพื้นฐานนั้นง่ายมาก เลือกหนึ่งในนั้นตามความต้องการทางธุรกิจเฉพาะ เพราะไม่มีปัญหาเรื่องความแข็งแรงและความแข็งแรงระหว่างแต่ละอินเตอร์เฟส
4. สปริงข้อมูล jpa แบบสอบถาม
1. สร้างแบบสอบถามโดยใช้ @Query
การใช้คำอธิบายประกอบ @Query นั้นง่ายมาก คุณเพียงแค่ต้องติดฉลากคำอธิบายประกอบในวิธีการที่ประกาศและให้คำสั่ง jp ql query นักพัฒนาหลายคนต้องการใช้พารามิเตอร์ชื่อแทนหมายเลขตำแหน่งเมื่อสร้าง JP QL และ @Query ยังให้การสนับสนุนสิ่งนี้ ในคำสั่ง JP QL จะมีการระบุพารามิเตอร์ผ่านรูปแบบของ ": ตัวแปร" และในเวลาเดียวกัน @Param จะถูกใช้ต่อหน้าพารามิเตอร์วิธีการเพื่อให้สอดคล้องกับพารามิเตอร์ที่มีชื่อใน JP QL นอกจากนี้นักพัฒนายังสามารถดำเนินการอัปเดตโดยใช้ @Query ในการทำเช่นนี้เราจำเป็นต้องใช้ @modifying เพื่อระบุการดำเนินการเป็นแบบสอบถามที่แก้ไขแล้วในขณะที่ใช้ @Query เพื่อให้เฟรมเวิร์กจะสร้างการดำเนินการที่อัปเดตในที่สุดไม่ใช่การดำเนินการแบบสอบถาม
เขียนอินเทอร์เฟซดังนี้:
/*** คำอธิบาย: แบบสอบถามที่กำหนดเอง เมื่อสปริงข้อมูล JPA ไม่สามารถให้ได้จำเป็นต้องใช้อินเทอร์เฟซที่กำหนดเอง วิธีนี้สามารถใช้งานได้ในเวลานี้*/ อินเทอร์เฟซสาธารณะ UserDefineByself ขยาย jParePository <ผู้ใช้, จำนวนเต็ม> {/ *** พารามิเตอร์ชื่อ* คำอธิบาย: แนะนำให้ใช้วิธีนี้คุณสามารถเพิกเฉยต่อตำแหน่งของพารามิเตอร์*/ @Query ("เลือกคุณจากผู้ใช้ /*** พารามิเตอร์ดัชนี* คำอธิบาย: ใช้? PlaceHolder*/ @Query ("เลือก u จากผู้ใช้ U โดยที่ U.Email =? 1") // 1 ระบุพารามิเตอร์แรกของผู้ใช้ FindUserByEmail (อีเมลสตริง); /*** คำอธิบาย: การอัปเดตสามารถทำได้ผ่าน @Modifying และ @Query* หมายเหตุ: ค่าส่งคืนของการแก้ไขแบบสอบถามสามารถเป็นโมฆะหรือ int/integer*/@modifying @Query ("UPDATE USER U SET U.NAME =: ชื่อที่ U.ID =: ID" - หมายเหตุ: @modifying Annotation มี clearautomatically การกำหนดค่า
มันบอกว่าบริบทการคงอยู่ของพื้นฐานสามารถล้างได้ซึ่งเป็นคลาส EntityManager เรารู้ว่าการใช้งาน JPA จะมีแคชรองนั่นคือหลังจากอัปเดตฐานข้อมูลหากคุณใช้วัตถุนี้ในภายหลังคุณจะตรวจสอบวัตถุ วัตถุนี้ถูกแคชในระดับแรก แต่ไม่ได้ซิงโครไนซ์กับฐานข้อมูล ในเวลานี้ Clearautomatically = True จะถูกใช้เพื่อรีเฟรชแคชระดับแรกของไฮเบอร์เนต มิฉะนั้นคุณจะอัปเดตวัตถุในอินเทอร์เฟซเดียวกันจากนั้นสอบถามวัตถุนี้จากนั้นวัตถุที่คุณพบยังคงเป็นสถานะก่อนหน้านี้ที่ไม่ได้อัปเดตมาก่อน
คลาสทดสอบ:
@runwith (springjunit4classrunner.class) @contextconfiguration (locations = {"classpath: applicationcontext-config.xml"}) @transactionConfiguration (defaultrollback = false) @Test โมฆะสาธารณะ Public TestFinduserByName () {ผู้ใช้ผู้ใช้ = dao.finduserByName ("chhliu"); assert.assertequals ("chhliu", user.getName ()); System.out.println (user.getName ()); } @Test โมฆะสาธารณะ testFinduserByEmail () {ผู้ใช้ผู้ใช้ = dao.finduserByEmail ("chhliu @.com"); assert.assertequals ("chhliu", user.getName ()); System.out.println (user.getName ()); } @Test โมฆะสาธารณะ TestUpDateUserById () {dao.updateUserById ("tanjie", 4); - จากรหัสทดสอบเราจะเห็นว่าเรากำหนดอินเทอร์เฟซเท่านั้นโดยไม่มีคลาสการใช้งานใด ๆ แต่ใช้ฟังก์ชั่นที่เราต้องการ
2. สร้างแบบสอบถามโดยใช้ @namedqueries
การสืบค้นชื่อเป็นฟังก์ชั่นที่จัดทำโดย JPA ที่แยกคำสั่งแบบสอบถามออกจากวิธีการสำหรับการแบ่งปันหลายวิธี Spring Data JPA ยังให้การสนับสนุนที่ดีสำหรับการสืบค้นที่มีชื่อ ผู้ใช้จะต้องกำหนดคำสั่ง Query ในไฟล์ ORM.XML หรือในรหัสตามข้อกำหนด JPA สิ่งเดียวที่พวกเขาต้องทำคือการปฏิบัติตามกฎการตั้งชื่อของ "domainclass.methodname ()" เมื่อตั้งชื่อคำสั่ง
การเขียนอินเทอร์เฟซ:
อินเทอร์เฟซสาธารณะ FindUserByNamedQueryRepository ขยาย jParePository <ผู้ใช้จำนวนเต็ม> {ผู้ใช้ findUserWithName (@param ("ชื่อ") ชื่อสตริง); - การเขียนชั้นเรียน:
@ENTITY @NamedQuery (value = {@NamedQuery (name = "user.finduserWithName", query = "เลือก u จากผู้ใช้ u u โดยที่ u.name =: name")}) // หมายเหตุ: หากมีหลายวิธีที่นี่คุณต้องใช้ @NamedQuery หากมีเพียงวิธีเดียวคุณสามารถใช้ @NamedQuery วิธีการเขียนมีดังนี้: @NamedQuery (name = "user.finduserWithName", query = "เลือกคุณจากผู้ใช้ u โดยที่ u.name =: ชื่อ") คลาสสาธารณะ FinduserByNamedQuery { / *** หมายเหตุ: คลาสเอนทิตีนี้จะต้องกำหนดไว้ที่นี่ - หมายเหตุ: ชิ้นส่วนที่ทำเครื่องหมายเป็นสีแดงในบทความจำเป็นต้องสอดคล้องกันโดยหนึ่งมิฉะนั้นพวกเขาจะไม่ตรงตามข้อกำหนดของ JPA
คลาสทดสอบ:
@runwith (springjunit4classrunner.class) @contextconfiguration (locations = {"classpath: applicationcontext-config.xml"}) @transactionConfiguration (defaultrollback = false) @Test โมฆะสาธารณะ Public TestFinduserByName () {ผู้ใช้ผู้ใช้ = dao.finduserWithName ("Caican"); System.out.println (json.tojsonstring (ผู้ใช้)); - 3. สร้างแบบสอบถามโดยการวิเคราะห์ชื่อวิธี
ตามชื่อที่แนะนำมันคือการสร้างแบบสอบถามตามชื่อของวิธีการ บางทีมันอาจฟังดูไม่น่าเชื่อในตอนแรก แต่หลังจากการทดสอบฉันพบว่าทุกอย่างเป็นไปได้
การเขียนอินเทอร์เฟซ:
อินเทอร์เฟซสาธารณะ SimpleConditionQueryRepository ขยาย jParePository <ผู้ใช้จำนวนเต็ม> { /*** คำอธิบาย: ตามกฎที่กำหนดโดยข้อมูลฤดูใบไม้ผลิวิธีการสอบถามเริ่มต้นด้วยการค้นหา | อ่าน | รับ* เมื่อมาถึงแบบสอบถามตามเงื่อนไขคุณสมบัติของเงื่อนไขเชื่อมต่อกับคำสำคัญตามเงื่อนไข ควรสังเกตว่า: ตัวอักษรตัวแรกของแอตทริบิวต์เงื่อนไขจะต้องเป็นตัวพิมพ์ใหญ่* / / *** หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง SQL: เลือก u จากผู้ใช้ u โดยที่ u.name =: ชื่อและ u.email =: อีเมล* ชื่อพารามิเตอร์คือตัวอักษรเริ่มต้น รายการ*/ ผู้ใช้ FindByNameAndEmail (ชื่อสตริงอีเมลสตริง); / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง sql: เลือก u จากผู้ใช้ u u โดยที่ u.name =? 1 หรือ u.password =? 2 */ list <ผู้ใช้> findByNameOrPassword (ชื่อสตริงรหัสผ่านสตริง); / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง sql: เลือก u จากผู้ใช้ u u u.id ระหว่าง? 1 และ? 2 */ list <ผู้ใช้> findByidBetween (จำนวนเต็มเริ่มต้น / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง sql: เลือก u จากผู้ใช้ u u u.id ระหว่าง? 1 และ? 2 */ list <ผู้ใช้> findByidBetween (จำนวนเต็มเริ่มต้น / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง SQL: เลือก u จากผู้ใช้ u โดยที่ U.ID <? 1 */ list <ผู้ใช้> findByidlessThan (สิ้นสุดจำนวนเต็ม); / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง SQL: เลือก u จากผู้ใช้ u ที่ U.ID>? 1 */ list <ผู้ใช้> findByIdGreaterthan (จำนวนเต็มเริ่มต้น); / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง SQL: เลือก u จากผู้ใช้ u โดยที่ u.name เป็น null */ list <ผู้ใช้> findByNameInull (); / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง sql: เลือก u จากผู้ใช้ u โดยที่ u.name ไม่ใช่ null */ list <ผู้ใช้> findByNameInnotNull (); / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง sql: เลือก u จากผู้ใช้ u u u.name ชอบ 1 */ list <ผู้ใช้> findBynamelike (ชื่อสตริง); / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง sql: เลือก u จากผู้ใช้ u ที่ u.name ไม่ชอบ? 1 */ list <ผู้ใช้> findbybynamenotlike (ชื่อสตริง); / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง SQL: เลือก u จากผู้ใช้ u โดยที่ U.Password =? 1 คำสั่งซื้อโดย U.ID DESC */ List <ผู้ใช้> findByPassWorderNyByIdDesc (รหัสผ่านสตริง); / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง SQL: เลือก u จากผู้ใช้ u u โดยที่ u.name <>? 1 */ list <ผู้ใช้> findBynamenot (ชื่อสตริง); / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง SQL: เลือก u จากผู้ใช้ u ที่ U.ID ใน? 1 */ list <ผู้ใช้> findByIdin (รายการ <จำนวนเต็ม> ids); / ** * หมายเหตุ: อินเทอร์เฟซนี้ที่นี่เทียบเท่ากับการส่ง SQL: เลือก u จากผู้ใช้ u ที่คุณไม่ได้อยู่ใน? 1 */ list <ผู้ใช้> findByIdNotin (รายการ <teger> ids); - คลาสทดสอบ (ส่วนความคิดเห็นคือคำสั่ง SQL ที่ส่งจริง):
@runwith (springjunit4classrunner.class) @contextconfiguration (locations = {"classpath: applicationcontext-config.xml"}) @transactionConfiguration (defaultrollback = false) /*** เลือก user0_.id เป็น id0_, user0_.account เป็น account0_, user0_.email เป็น email0_, user0_.name เป็น name0_, user0_.password เป็น password0_ จากผู้ใช้ user0_ โดยที่ user0_.name =? และ user0_.email =? จำกัด ? */ @Test โมฆะสาธารณะ Public TestFinduserByNameAndEmail () {ผู้ใช้ผู้ใช้ = dao.findbynameandemail ("chhliu", "chhliu @.com"); System.out.println (json.tojsonstring (ผู้ใช้)); } /*** เลือก user0_.id เป็น id1_, user0_.account เป็น account1_, user0_.email เป็น email1_, user0_.name เป็นชื่อ 1_, user0_.password เป็นรหัสผ่าน 1_ จากผู้ใช้ user0_ โดยที่ user0_.name =? หรือ user0_.password =? */ @test โมฆะสาธารณะ Public TestFinduserByNameOrPassword () {รายการ <ผู้ใช้> ผู้ใช้ = dao.findbynameorpassword ("chhliu", "123456"); System.out.println (json.tojsonstring (ผู้ใช้)); } /*** เลือก user0_.id เป็น id1_, user0_.account เป็น account1_, user0_.email เป็น email1_, user0_.name เป็นชื่อ 1_, user0_.password เป็นรหัสผ่าน 1_ จากผู้ใช้ user0_ และ ? */ @Test โมฆะสาธารณะ TestFindByIdBetween () {รายการ <ผู้ใช้> ผู้ใช้ = dao.findbyidBetween (5, 8); System.out.println (json.tojsonstring (ผู้ใช้)); } /*** เลือก user0_.id เป็น id1_, user0_.account เป็น account1_, user0_.email เป็น email1_, user0_.name เป็นชื่อ 1_, user0_.password เป็นรหัสผ่าน 1_ จากผู้ใช้ user0_ โดยที่ผู้ใช้ 0_.id <? */ @Test โมฆะสาธารณะ TestFindByidlessThan () {รายการ <ผู้ใช้> ผู้ใช้ = dao.findbyidlessthan (4); System.out.println (json.tojsonstring (ผู้ใช้)); } /*** เลือก user0_.id เป็น id0_, user0_.account เป็น account0_, user0_.email เป็น email0_, user0_.name เป็นชื่อ 0_, user0_.password เป็นรหัสผ่าน */ @Test Public Void TestFindByIdGreaterThan () {รายการ <ผู้ใช้> ผู้ใช้ = dao.findbyidGreaterthan (6); System.out.println (json.tojsonstring (ผู้ใช้)); } / ** * เลือก user0_.id เป็น id0_, user0_.account เป็น account0_, user0_.email เป็น email0_, user0_.name เป็น name0_, user0_.password เป็นรหัสผ่าน 0_ จากผู้ใช้ user0_ โดยผู้ใช้ System.out.println (json.tojsonstring (ผู้ใช้)); } / ** * เลือก user0_.id เป็น id1_, user0_.account เป็น account1_, user0_.email เป็น email1_, user0_.name เป็น name1_, user0_.password เป็นรหัสผ่าน 1_ จากผู้ใช้ user0_ ที่ผู้ใช้ dao.findbynameinnotnull (); System.out.println (json.tojsonstring (ผู้ใช้)); } /*** เลือก user0_.id เป็น id1_, user0_.account เป็น account1_, user0_.email เป็น email1_, user0_.name เป็น name1_, user0_.password เป็น password1_ จากผู้ใช้ user0_ โดยที่ user0_.name ชอบ? */ @Test Public Void TestFindByNamelike () {รายการ <ผู้ใช้> ผู้ใช้ = dao.findbynamelike ("chhliu"); System.out.println (json.tojsonstring (ผู้ใช้)); } /*** เลือก user0_.id เป็น id0_, user0_.account เป็น account0_, user0_.email เป็น email0_, user0_.name เป็นชื่อ 0_, user0_.password เป็นรหัสผ่าน */ @Test โมฆะสาธารณะ TestFindByNamenotlike () {รายการ <ผู้ใช้> ผู้ใช้ = dao.findbynamenotlike ("chhliu"); System.out.println (json.tojsonstring (ผู้ใช้)); } /*** เลือก user0_.id เป็น id0_, user0_.account เป็น account0_, user0_.email เป็น email0_, user0_.name เป็นชื่อ 0_, user0_.password เป็นรหัสผ่าน สั่งซื้อโดย user0_.id desc */ @test โมฆะสาธารณะ public testFindBypassWorderDerByIddesc () {list <ผู้ใช้> ผู้ใช้ = dao.findBypassWordOrderByIdDesc ("123456"); System.out.println (json.tojsonstring (ผู้ใช้)); } /*** เลือก user0_.id เป็น id1_, user0_.account เป็น accountion1_, user0_.email เป็น email1_, user0_.name เป็นชื่อ 1_, user0_.password เป็นรหัสผ่าน 1_ จากผู้ใช้ user0_ โดยที่ผู้ใช้ 0_.name <>? */ @Test โมฆะสาธารณะ TestFindByNamEnot () {รายการ <ผู้ใช้> ผู้ใช้ = dao.findbynamenot ("chhliu"); System.out.println (json.tojsonstring (ผู้ใช้)); } / ** * เลือก user0_.id เป็น id1_, user0_.account เป็น account1_, user0_.email เป็น email1_, user0_.name เป็น name1_, user0_.password เป็น password1_ จากผู้ใช้ user0_ user0_.id ใน (? arraylist <integer> (array.aslist (3,4,6,8))); System.out.println (json.tojsonstring (ผู้ใช้)); } / ** * เลือก user0_.id เป็น id0_, user0_.account เป็น account0_, user0_.email เป็น email0_, user0_.name เป็น name0_, user0_.password เป็น password0_ จากผู้ใช้ user0_ user0_.id ไม่ได้อยู่ใน (? arraylist <integer> (array.aslist (3, 4, 6, 8))); System.out.println (json.tojsonstring (ผู้ใช้)); - ที่นี่เรากำหนดอินเทอร์เฟซเดียวเท่านั้น มีเพียงวิธีการในอินเทอร์เฟซ แต่ไม่มีการใช้งาน แต่การดำเนินการต่าง ๆ เสร็จสมบูรณ์
หลังจากเห็นสิ่งนี้หลายคนอาจถามว่า Spring Data JPA ทำได้อย่างไร? ปรากฎว่าเมื่อเฟรมเวิร์กวิเคราะห์ชื่อวิธีมันจะสกัดกั้นคำนำหน้าส่วนเกินของชื่อวิธีเช่นค้นหา, findby, อ่าน, อ่าน, อ่าน, รับ, getby, จากนั้นแยกวิเคราะห์ส่วนที่เหลือ และหากพารามิเตอร์สุดท้ายของวิธีการเรียงลำดับหรือประเภทที่สามารถแยกออกได้ข้อมูลที่เกี่ยวข้องจะถูกสกัดสำหรับการเรียงลำดับหรือการเพิกถอนแบบสอบถามตามกฎ เมื่อสร้างแบบสอบถามเราจะแสดงโดยใช้ชื่อแอตทริบิวต์ในชื่อวิธีเช่น findByidin () เมื่อเฟรมเวิร์กแยกวิเคราะห์วิธีนี้มันจะกำจัด Findby ก่อนแล้วจึงวิเคราะห์แอตทริบิวต์ที่เหลือ
เมื่อสอบถามมักจะจำเป็นต้องสืบค้นตามแอตทริบิวต์หลายตัวในเวลาเดียวกันและเงื่อนไขการสืบค้นก็มีรูปแบบที่แตกต่างกัน (มากกว่าค่าที่แน่นอนในช่วงที่กำหนด ฯลฯ ) Spring Data JPA มีคำหลักบางคำสำหรับการแสดงแบบสอบถามแบบมีเงื่อนไขดังนี้:
และ --- เทียบเท่ากับคำหลักและคำหลักใน SQL เช่น FindByUserNameAndPassword (String user, Striang PWD)
หรือ --- เทียบเท่ากับหรือคำหลักใน SQL เช่น FindByUserNameOraddress (ผู้ใช้สตริง, สตริง addr)
ระหว่าง --- ระหว่างคำหลักเทียบเท่ากับ SQL เช่น findBysalaryBetween (int max, int min)
Lessthan --- เทียบเท่ากับ "<" ใน SQL เช่น findBysalarylessThan (int max)
Greaterthan --- เทียบเท่ากับ ">" ใน SQL เช่น findbysalarygreaterthan (int min)
isnull --- เทียบเท่ากับ "เป็น null" ใน SQL เช่น findByUserNameIsnull ()
isnotnull --- เทียบเท่ากับ "ไม่เป็นโมฆะ" ใน SQL เช่น findByUserNameInnotNull ()
notnull --- เทียบเท่ากับ isnotnull
ชอบ --- เทียบเท่ากับ "Like" ใน SQL เช่น FindByUserNamelike (ผู้ใช้สตริง)
ไม่เหมือน --- เทียบเท่ากับ "ไม่ชอบ" ใน SQL เช่น FindByUserNamenotlike (ผู้ใช้สตริง)
orderby ---- เทียบเท่ากับ "สั่งซื้อ" ใน SQL เช่น findByUserNameOrderBysalaryAsc (ผู้ใช้สตริง)
ไม่ --- เทียบเท่ากับ "! =" ใน SQL ตัวอย่างเช่น FindByUserNamenot (ผู้ใช้สตริง)
ใน --- เทียบเท่ากับ "in" ใน SQL เช่น FindByUserNamein (คอลเลกชัน <String> Userlist) พารามิเตอร์ของวิธีการอาจเป็นประเภทการรวบรวมหรืออาร์เรย์หรือพารามิเตอร์ความยาวไม่ จำกัด
Notin --- เทียบเท่ากับ "ไม่อยู่ใน" ใน SQL เช่น FindByUserNamenotin (คอลเลกชัน <String> Userlist) พารามิเตอร์ของวิธีการอาจเป็นประเภทการรวบรวมหรืออาร์เรย์หรือพารามิเตอร์ความยาวไม่ จำกัด
5. คำสั่งของการสร้างแบบสอบถาม
เมื่อสร้างวัตถุพร็อกซีสำหรับอินเทอร์เฟซหากพบว่ามีหลายสถานการณ์ข้างต้นพร้อมใช้งานในเวลาเดียวกันกลยุทธ์ใดที่ควรนำมาใช้ก่อน ในการทำเช่นนี้ <jpa: ที่เก็บ> จัดเตรียมคุณสมบัติการสืบค้น-ลุคอัพ-สตริตี้เพื่อระบุลำดับของการค้นหา มันมีสามค่าต่อไปนี้:
สร้าง --- สร้างแบบสอบถามโดยการแก้ไขชื่อวิธี แม้ว่าจะมีการจับคู่ที่มีชื่อว่า Query หรือคำสั่งค้นหาที่ระบุโดยวิธีการผ่าน @Query มันจะถูกละเว้น
create-if-not-found --- หากวิธีการระบุคำสั่งการสืบค้นผ่าน @Query การสอบถามจะถูกนำไปใช้; ถ้าไม่พบว่ามีการค้นหาแบบสอบถามที่ตรงตามเกณฑ์หรือไม่หากพบว่ามีการใช้แบบสอบถามที่มีชื่อหรือไม่ if neither is found, the query is created by parsing the method name. This is the default value of the query-lookup-strategy property.
use-declared-query --- 如果方法通过@Query 指定了查询语句,则使用该语句实现查询;如果没有,则查找是否定义了符合条件的命名查询,如果找到,则使用该命名查询;如果两者都没有找到,则抛出异常。
六、Spring Data JPA 对事务的支持
Careful readers may see some clues from the above code. When we use Spring data JPA, we just define the interface. When using it, we can just inject it directly, and we do not do any processing related to things. But in fact, things have already achieved results. ทำไมถึงเป็นเช่นนี้?
默认情况下,Spring Data JPA 实现的方法都是使用事务的。针对查询类型的方法,其等价于@Transactional(readOnly=true);增删改类型的方法,等价于@Transactional。可以看出,除了将查询的方法设为只读事务外,其他事务属性均采用默认值。
如果用户觉得有必要,可以在接口方法上使用@Transactional 显式指定事务属性,该值覆盖Spring Data JPA 提供的默认值。同时,开发者也可以在业务层方法上使用@Transactional 指定事务属性,这主要针对一个业务层方法多次调用持久层方法的情况。持久层的事务会根据设置的事务传播行为来决定是挂起业务层事务还是加入业务层的事务。
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น