بيئة تطوير هذه المقالة: Spring-Boot: 2.0.3.release + Java1.8
لماذا تفعل
الحذف الناعم: أي أنه لا يتم إجراء عملية حذف حقيقية. نظرًا لوجود الربط (المفاتيح الخارجية) بين كياناتنا ، فإن حذف بعض البيانات سيؤدي إلى بيانات أخرى غير مكتملة. على سبيل المثال ، المعلم في فئة الكمبيوتر 1801 هو Zhang San. في هذا الوقت ، إذا حذفنا Zhang San ، ثم عندما نستفسر عن فئة الكمبيوتر 1801 ، نظرًا لأن Zhang San لم يعد موجودًا ، فسنقوم بالإبلاغ عن خطأ EntityNotFound. بطبيعة الحال ، في قاعدة بيانات ذات قيود رئيسية خارجية ، إذا كان Zhang San مدرسًا في الفصل 1801 ، فسوف نقوم بحذف Zhang San مباشرة والإبلاغ عن استثناء ملزم. بمعنى آخر ، لا يمكن تنفيذ سلوك حذف Zhang San مباشرة.
لكن في بعض الأحيان ، لدينا الحاجة إلى حذفه. على سبيل المثال ، يترك الموظف ثم نريد حذف الموظف في إدارة الموظفين. ومع ذلك: لدى الموظف تاريخ في جدول البيانات. على سبيل المثال ، سجلنا أن بنية بيانات الفصل الدراسي الثاني من عام 2017 كانت تشانغ سانجيو. بعد ذلك ، بسبب وجود قيود ، سيتم الإبلاغ عن خطأ ملزم عند حذف Zhang San. بمعنى آخر: الإحراج الذي يجب حذفه ولكن لا يمكن حذفه.
هذا يستخدم الحذف الناعم المذكور في هذه المقالة. يعني ما يسمى الحذف الناعم أنني لا أحذف البيانات في جدول البيانات حقًا ، ولكن بدلاً من ذلك أضف علامة إلى السجل الذي يجب حذفه.
يدعم Spring JPA الحذف الناعم ، يمكننا العثور على المزيد من المقالات ذات الجودة الجيدة لحل هذه المشكلة. الخطوات العامة هي: 1. إضافة sqldelete ("تحديث xxxx set deleted = 1 where id = ?")。2.加入@Where(clause = "deleted = false") . لكن هذا الحل ليس مثاليًا. تجلى على وجه التحديد في:
لنأخذ Zhang San كمدرس في الفصل 1801 كمثال.
بعد إضافة التعليق التوضيحي ، يمكننا بالفعل حذف Zhang San بنجاح. بعد عملية الحذف ، قمنا بفحص جدول البيانات وسجل Zhang San لا يزال موجودًا بالفعل. ولكن في هذا الوقت ، إذا قمنا all أو استعلام page ، فسوف نحصل على خطأ 500 EntiyNotFound . هذا لأنه خلال جميع الاستعلام ، يضيف JPA تلقائيًا معلمات الاستعلام في @Where . بسبب deleted = true للبيانات المرتبطة به ، استثناء من أنه لم يتم العثور على الكيان المرتبط.
ولكن الحقيقة هي: على الرغم من حذف الكيان ، إلا أنه لا يزال موجودًا ، ونريد تطبيقه على استعلام الجمعية. ليس من المتوقع أن يكون لها استثناء 500 EntiyNotFound .
حل هذه المقالة ينفذ:
حل
تطبيق
التهيئة
قم بإنشاء ثلاثة كيانات جديدة: ClazzTest, Clazz, Teacher ، وإنشاء كيان فئة BaseEntity جديدة. حيث يتم استخدام ClazzTest لإظهار الاستثناء الذي يحدث عند استخدام @Where(clause = "deleted = false") .
package com.mengyunzhi.springbootsamplecode.softdelete.entity ؛ import javax.persistence.mappedsuperClass ؛ mappedsuperClasspublic class {private boolean deleded = false ؛ // setter و getter} package com.mengyunzhi.springBOOTSampleCode.SoftDelete.entity ؛ استيراد org.hibernate.annotations.sqldelete ؛ استيراد javax.persistence.entity `klass` set deleted = 1 where id =؟") class public klass يمتد baseentity {idgeneratedValue private id ؛ اسم السلسلة الخاصة ؛ // setter و getter} @entity @sqldelete (sql = "update` klass_test` set set deleted = 1 where id =؟ ") @where (" eleded = false ") class klasstest يمتد baseentity {dedgeneratedValue private id ؛ اسم السلسلة الخاصة ؛} أعد كتابة crudrepository
package com.mengyunzhi.springbootsamplecode.softdelete.core ؛ استيراد org.springframework.data.jpa.repository.query javax.transaction.transactional ؛ import java.util.Optional ؛/*** تطبيق soft delete* default @yere (cind = "deleted = 0") سيؤدي إلى استثناء من ObjectNotfound عند إجراء استعلام مرتبط داخل hibernate* إعادة تعريف الواجهة هنا* المرجع: https://stackoverflow.com/questions/19323557/handling-soft-deletes-with-spring-jpa/22202469 * @Auuthor mengyunzhi team team of hebei of technology */ @norepositorybevanpangupultiletory <t t ، t ، OverRideTransActional Query ("حدد e من #{ #entityName} e حيث e.id =؟ 1 و e.deleted = false") اختياري <T> findById (معرف المعرف) ؛ OverRideTransActional الافتراضي boolean arexbyid (id id) {return findbyid (id) .ispresent () ؛ } OverRideTransActional Query ("حدد e من #{ #entityName} e حيث e.deleted = false") itervable <T> findall () ؛ OverRideTransActionAl Query ("حدد E من #{ #entityName} e حيث e.id في؟ 1 و e.deleted = false") Itervable <T> findallbyid (ITERBLE <ID> IDS) ؛ OverRideTransActional Query ("حدد العد (e) من #{ #entityName} e حيث قم بإنشاء فصل مستودع جديد
وراثة الربيع crudrepository.
/*** class* author panjie*/public interface KlassRepository يمتد softdeletecrudrepository <klass ، long> {} الواجهة العامة KlasStestRepository تمتد SoftDeletCrudRepository <KlasStest ، Long> {} الواجهة العامة TeachRrepository تمتد crudrepository <المعلم ، طويل> {} امتحان
package com.mengyunzhi.springBootsampleCode.softdelete.repository ؛ استيراد com.mengyunzhi.springbortamplecode.softdelete.entity.klass com.mengyunzhi.springbootsamplecode.softdelete.entity.teacher ؛ import org.assertj.core.api.assertions ؛ import org.junit.test ؛ import org.junit.runner.runwith ؛ org.springframework.beans.factory.annotation org.springframework.test.context.Junit4 loggerfactory.getLogger (TeachRrepositoryTest.class) ؛ Autowired KlassRepository KlassRepository ؛ @autowired KlasSteStrepository KlasSteStrepository ؛ Autowired TeachRrepository TeachRrepository ؛ Test public void findbyid () {logger.info ("إنشاء مدرس جديد مع Klass و KlasStest") ؛ Klass Klass = New Klass () ؛ klassrepository.save (klass) ؛ Klasstest KlasStest = New KlasStest () ؛ KlasStestrepository.save (Klasstest) ؛ المعلم المعلم = معلم جديد () ؛ المعلم. المعلم. TeacherRepository.save (المعلم) ؛ logger.info ("ابحث عن المعلم ، وأكد أنه تم العثور على الكيان ، ولم يحدث استثناء") ؛ اختياري <Sethand> TeacherOptional = TeacherRepository.FindByid (Teacher.getID ()) ؛ Assertions.AssertThat (teacheroptional.get ()). isnotnull () ؛ logger.info ("حذف KLASS المرتبطة ، ثم ابحث عن كيان المعلم ، يؤكد أنه تم العثور على الكيان ، ولم يحدث استثناء. التأكيد على أنه لا يزال هناك كيان KLASS المحذوف في كيان المعلم") ؛ klassrepository.deleteByid (klass.getid ()) ؛ المعلم = TeacherRepository.findbyid (teacher.getId ()) ؛ Assertions.AssertThat (teacheroptional.get ()). isnotnull () ؛ Assertions.AssertThat (TeacherOptional.get (). getKlass (). logger.info ("ابحث عن قائمة المعلمين ، لم يحدث استثناء. تأكد من وجود سجل كيان KLASS المحذوف في كيان المعلم") ؛ قائمة <Sethor> TeacherList = (LIST <Sethor>) TeacherRepository.Findall () ؛ لـ (Teacher Teacher1: Teacherlist) {Assertions.AssertThat (teacher1.getklass (). } logger.info ("حذف klasstest المرتبطة ، ثم البحث عن كيان المعلم ، يؤكد أنه تم العثور على klasstest المحذوفة") ؛ klasSteStrepository.DeleteById (klasstest.getid ()) ؛ المعلم = TeacherRepository.findbyid (teacher.getId ()) ؛ Assertions.AssertThat (teacheroptional.get ()). isnotnull () ؛ Assertions.assertThat (teacheroptional.get (). getKlasStest (). logger.info ("ابحث عن قائمة المعلمين مرة أخرى ، تؤكد أن jpaObjectReTRIVALFailureException ستحدث (استثناء entityNotfound يتم اكتشافه وتغليفه وإلقاءه)") ؛ catchexception منطقية = خطأ ؛ حاول {teacherrepository.findall () ؛ } catch (jPaObjectRevErivealFailureException e) {catchException = true ؛ } Assertions.AssertThat (catchException) .Istrue () ؛ }} لخص
عند استخدام DefaultSQLdElete و @yere annotation ، يمكن لبيانات JPA التعامل مع طريقة findbyid () بشكل جيد ، لكنها تفشل في التعامل مع طريقة findall () بشكل جيد. هنا ، قمنا بتنفيذ طريقة إعادة كتابة طريقة crunrepository. عندما نقوم بإجراء الاستعلامات الأساسية ، نستخدم طريقتنا المخصصة لإضافة حذف = صحيح. عندما تجري JPA استعلامًا للاتحاد ، نظرًا لأننا لا نضع التعليق التوضيحي @yere ، سيتم الاستعلام عن جميع البيانات ، وبالتالي تجنب الاستثناء الذي يحدث أحيانًا عند إجراء الاستعلام Foundall ().
في هذه المقالة ، نقدم فقط بعض رمز المثال.
إذا كنت بحاجة إلى الرمز الكامل ، يرجى النقر على: https://github.com/mengyunzhi/SpringBootsampleCode/tree/master/softdelete.
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.