สภาพแวดล้อมการพัฒนาของบทความนี้: Spring-Boot: 2.0.3.release + Java1.8
ทำไมต้องทำ
การลบแบบอ่อน: นั่นคือไม่มีการดำเนินการลบจริง เนื่องจากการมีอยู่ของการเชื่อมโยง (กุญแจต่างประเทศ) ระหว่างหน่วยงานของเราการลบข้อมูลบางอย่างจะนำไปสู่ข้อมูลอื่นที่ไม่สมบูรณ์ ตัวอย่างเช่นครูในคลาสคอมพิวเตอร์ 1801 คือจางซาน ในเวลานี้ถ้าเราลบจางซานแล้วเมื่อเราสอบถามคลาสคอมพิวเตอร์ 1801 เนื่องจากจางซานไม่มีอยู่อีกต่อไปเราจะรายงานข้อผิดพลาดของเอนทิตีโน แน่นอนในฐานข้อมูลที่มีข้อ จำกัด ของคีย์ต่างประเทศถ้าจางซานเป็นครูในชั้นเรียน 1801 เราจะลบจางซานโดยตรงและรายงานข้อยกเว้นที่มีผลผูกพัน กล่าวอีกนัยหนึ่งพฤติกรรมของการลบจางซานไม่สามารถดำเนินการได้
แต่บางครั้งเราจำเป็นต้องลบมัน ตัวอย่างเช่นพนักงานออกจากนั้นเราต้องการลบพนักงานในการจัดการพนักงาน อย่างไรก็ตาม: พนักงานมีประวัติในตารางข้อมูล ตัวอย่างเช่นเราบันทึกว่าโครงสร้างข้อมูลของภาคการศึกษาที่สองของปี 2560 คือจางซันจีโอ จากนั้นเนื่องจากการมีอยู่ของข้อ จำกัด จะมีการรายงานข้อผิดพลาดที่มีผลผูกพันเมื่อลบจางซาน กล่าวอีกนัยหนึ่ง: ความอับอายที่ควรลบ แต่ไม่สามารถลบได้
สิ่งนี้ใช้การลบแบบนุ่มนวลที่กล่าวถึงในบทความนี้ การลบแบบนุ่มนวลที่เรียกว่าฉันไม่ได้ลบข้อมูลในตารางข้อมูลจริง ๆ แต่แทนที่จะเพิ่มเครื่องหมายลงในบันทึกว่าจะลบออกหรือไม่
Spring JPA รองรับการลบอย่างนุ่มนวลเราสามารถค้นหาบทความเพิ่มเติมที่มีคุณภาพดีในการแก้ปัญหานี้ ขั้นตอนทั่วไปคือ: 1. เพิ่ม @SqldElete ("อัปเดต XXXX set deleted = 1 where id = ?")。2.加入@Where(clause = "deleted = false") แต่วิธีแก้ปัญหานี้ไม่สมบูรณ์แบบ ประจักษ์โดยเฉพาะใน:
ลองใช้จางซานเป็นครูในชั้น 1801 เป็นตัวอย่าง
หลังจากเพิ่มคำอธิบายประกอบเราสามารถลบจางซานได้สำเร็จ หลังจากการดำเนินการลบเราตรวจสอบตารางข้อมูลและบันทึกของจางซานยังคงอยู่ที่นั่น แต่ในเวลานี้ถ้าเราทำแบบสอบถาม all หรือ page เราจะได้รับข้อผิดพลาด 500 EntiyNotFound นี่เป็นเพราะในระหว่างการสืบค้นทั้งหมด JPA จะเพิ่มพารามิเตอร์การสืบค้นโดยอัตโนมัติใน @Where เนื่องจาก deleted = true ของข้อมูลที่เกี่ยวข้องยกเว้นว่าไม่พบเอนทิตีที่เกี่ยวข้อง
แต่ความจริงก็คือ: ถึงแม้ว่าเอนทิตีจะถูกลบ แต่ก็ยังอยู่ที่นั่นและเราต้องการนำไปใช้กับการสืบค้นสมาคม ไม่คาดว่าจะมีข้อยกเว้น 500 EntiyNotFound
วิธีแก้ปัญหาของบทความนี้ใช้:
สารละลาย
การดำเนินการ
การเริ่มต้น
สร้างสามหน่วยงานใหม่: ClazzTest, Clazz, Teacher และสร้างเอนทิตีคลาสนามธรรม BaseEntity ใหม่ โดยที่ ClazzTest ถูกใช้เพื่อแสดงข้อยกเว้นที่เกิดขึ้นเมื่อใช้ @Where(clause = "deleted = false")
แพ็คเกจ com.mengyunzhi.springbootsamplecode.softdelete.entity; นำเข้า Javax.persistence.mappedSuperClass; @MappedSuperClassPublic คลาส Abstract Baseentity // setter และ getter}
แพ็คเกจ com.mengyunzhi.springbootsamplecode.softdelete.entity นำเข้า org.hibernate.annotations.sqldelete; นำเข้า Javax.persistence.entity; นำเข้า javax.persistence.generatedValue; นำเข้า Javax.persistence.id; `klass` set deleeted = 1 โดยที่ id =?") คลาสสาธารณะ klass ขยาย baseentity {@id @id @generatedValue ส่วนตัว Long id; ชื่อสตริงส่วนตัว; // setter และ getter} @entity @sqldelete (sql = "อัปเดต` klass_test` set deleeted = 1 โดยที่ id =? ") @where (clause =" deleted = false ") คลาสสาธารณะ Klasstest ขยาย baseentity {@id @generatedValue ส่วนตัว ชื่อสตริงส่วนตัว;} เขียนซ้ำ crudrepository
แพ็คเกจ com.mengyunzhi.springbootsamplecode.softdelete.core; นำเข้า org.springframework.data.jpa.repository.query; นำเข้า org.springframework.data.repository.crudrepository; javax.transaction.transactional; นำเข้า java.util.optional;/*** ใช้ soft delete* เริ่มต้น @where (clause = "deleted = 0") จะทำให้เกิดข้อยกเว้นของ ObjectNotFound เมื่อทำการสืบค้นที่เกี่ยวข้อง https://stackoverflow.com/questions/19323557/handling-soft-deletes-with-spring-jpa/22202469 * @author mengyunzhi ทีมพัฒนาซอฟต์แวร์ของ Hebei University of Technology @Override @Transactional @Query ("เลือก E จาก #{ #entityName} e โดยที่ E.ID =? 1 และ E.Deleted = FALSE") ตัวเลือก <t> findById (รหัสรหัส); @Override @Transactional Boolean เริ่มต้นมี ExistSbyId (ID ID) {return findById (id) .ispresent (); } @Override @Transactional @Query ("เลือก E จาก #{ #entityName} e โดยที่ e.deleted = false") iterable <t> findall (); @Override @Transactional @Query ("เลือก E จาก #{ #entityName} e ที่ไหน e.id ใน? 1 และ e.deleted = false") iterable <t> findallById (iterable <id> ids); @Override @Transactional @Query ("เลือกนับ (e) จาก #{ #entityName} e โดยที่ e.deleted = false") long count ();} สร้างคลาสคลังสินค้าใหม่
การสืบทอด crudrepository ของฤดูใบไม้ผลิ
/*** คลาส* @author panjie*/ส่วนต่อประสานสาธารณะ klassrepository ขยาย softdeletecrudrepository <klass, long> {} อินเทอร์เฟซสาธารณะ Klasstestrepository ขยาย SoftDeleTeCrudRepository <Klasstest, Long> {} อินเทอร์เฟซสาธารณะ teacherrepository ขยาย crudrepository <ครู, ยาว> {} ทดสอบ
แพ็คเกจ com.mengyunzhi.springbootsamplecode.softdelete.repository; นำเข้า com.mengyunzhi.springbootbootbootsamplecode.softdelete.entity.klass; นำเข้า com.mengyunzhi.springbootsamplecode.softdelete. com.mengyunzhi.springbootsamplecode.softdelete.entity.teacher; นำเข้า org.assertj.core.api.assertions; นำเข้า org.junit.test; นำเข้า org.junit.runner.runwith; org.springframework.beans.factory.annotation.autoWired; นำเข้า org.springframework.boot.test.context.springboottest; นำเข้า org.springframework.orm.jpa.jpaobjectretrivealfailureexception; org.springframework.test.context.junit4.springrunner; นำเข้า java.util.list; นำเข้า java.util.optional;/** * @author panjie */@springboottest@runwith LoggerFactory.getLogger (TeacherRepositoryTest.class); @autowired klassrepository klassrepository; @autowired klasstestrepository klasstestrepository; @autowired TeacherRepository TeacherRepository; @Test โมฆะสาธารณะ public findById () {logger.info ("สร้างครูใหม่กับ Klass และ Klasstest"); klass klass = new klass (); KlassRepository.save (Klass); Klasstest Klasstest = new Klasstest (); Klasstestrepository.save (Klasstest); ครูครู = ครูใหม่ (); ครู Setklass (Klass); ครู Setklasstest (Klasstest); Teacherrepository.save (ครู); logger.info ("มองหาครูยืนยันว่าพบเอนทิตีและไม่มีข้อยกเว้นเกิดขึ้น"); ตัวเลือก <Teacher> TeacherOptional = TeacherRepository.FindById (Teacher.getId ()); assertions.assertthat (teacheroptional.get ()). isnotnull (); logger.info ("ลบ Klass ที่เกี่ยวข้องจากนั้นค้นหานิติบุคคลครูยืนยันว่าพบนิติบุคคลไม่มีข้อยกเว้นใด ๆ ยืนยันว่ายังมีนิติบุคคล Klass ที่ถูกลบในกิจการครู"); KlassRepository.deleteByid (klass.getId ()); TeacherOptional = TeacherRepository.FindById (teacher.getId ()); assertions.assertthat (teacheroptional.get ()). isnotnull (); assertions.assertthat (teacheroptional.get (). getKlass (). getId ()). isequalto (klass.getId ()); logger.info ("มองหารายชื่อครูไม่มีข้อยกเว้นยืนยันว่ามีบันทึกเอนทิตี Klass ที่ถูกลบในหน่วยงานครู"); รายการ <Teacher> TeacherList = (รายการ <Teacher>) TeacherRepository.FINDALL (); สำหรับ (อาจารย์ 1: TeacherList) {assertions.assertthat (ครู 1.getKlass (). getId ()). isequalto (klass.getId ()); } logger.info ("ลบ Klasstest ที่เกี่ยวข้องจากนั้นค้นหานิติบุคคลครูยืนยันว่าพบ Klasstest ที่ถูกลบ"); klasstestrepository.deleteById (klasstest.getId ()); TeacherOptional = TeacherRepository.FindById (teacher.getId ()); assertions.assertthat (teacheroptional.get ()). isnotnull (); assertions.assertthat (Teacheroptional.get (). getKlasstest (). getId ()). isequalto (klasstest.getId ()); logger.info ("ค้นหารายชื่อครูอีกครั้งยืนยันว่า jpaobjectrerivealfailureexception จะเกิดขึ้น (ข้อยกเว้น entitynotfound ถูกจับ, encapsulated และโยน)"); บูลีน catchException = false; ลอง {teacherrepository.findall (); } catch (jpaobjectretrerievalureexception e) {catchException = true; } assertions.assertthat (catchException). istrue (); - สรุป
เมื่อใช้ค่าเริ่มต้น @SQLDELETE และ @WHEREWASH ANNONTATION ข้อมูล JPA สามารถจัดการวิธี FindByID () ได้เป็นอย่างดี แต่มันไม่สามารถจัดการวิธีการค้นหา () ได้เป็นอย่างดี ที่นี่เราได้ใช้วิธีการเขียนวิธีการ crunrepository ใหม่ เมื่อเราจะทำการสืบค้นพื้นฐานเราใช้วิธีการที่กำหนดเองเพื่อเพิ่ม DELETED = TRUE เมื่อ JPA ดำเนินการสืบค้นสมาคมเนื่องจากเราไม่ได้ตั้งค่าคำอธิบายประกอบ @where ข้อมูลทั้งหมดจะถูกสืบค้นดังนั้นจึงหลีกเลี่ยงข้อยกเว้นที่เกิดขึ้นบางครั้งเมื่อทำการค้นหา Foundall ()
ในบทความนี้เราให้รหัสตัวอย่างเท่านั้น
หากคุณต้องการรหัสที่สมบูรณ์โปรดคลิก: https://github.com/mengyunzhi/springbootsamplecode/tree/master/softdelete
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น