Среда разработки этой статьи: Spring-Boot: 2.0.3. Release + Java1.8
Зачем делать
Мягкое удаление: то есть не выполняется реальная операция удаления. Из -за существования связывания (иностранных ключей) между нашими организациями удаление некоторых данных приведет к неполным другим данным. Например, учитель в компьютерном классе 1801 года - Чжан Сан. В настоящее время, если мы удалим 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") . Но это решение не идеально. В частности, проявляется в:
Давайте возьмем Чжан Сан в качестве учителя в классе 1801 года в качестве примера.
После добавления аннотации мы действительно можем успешно удалить Zhang San. После операции удаления мы проверили таблицу данных, а запись Чжан Сан действительно все еще там. Но в настоящее время, если мы сделаем all или page запрос, мы получим ошибку 500 EntiyNotFound . Это потому, что во время всего запроса JPA автоматически добавляет параметры запроса в @Where . Из -за deleted = true для связанных данных, исключение, что связанная сущность не найдена.
Но дело в том, что, хотя сущность удалена, она все еще там, и мы хотим применить его к запросу ассоциации. Не ожидается, что у него будет 500 EntiyNotFound Exception.
Решает решение этой статьи:
Решение
Выполнение
инициализация
Создайте три новых сущности: ClazzTest, Clazz, Teacher , и создайте новую абстрактную классную BaseEntity . Где ClazzTest используется для демонстрации исключения, которое происходит при использовании @Where(clause = "deleted = false") .
пакет com.mengyunzhi.springbootsamplecode.softdelete.entity; импорт javax.persistence.mappedsuperclass; @mappedsuperclasspublic Abstract Class Baseentity {Private Boolean Deleted = false; // setter and getter} пакет com.mengyunzhi.springbootsamplecode.softdelete.entity; import org.hibernate.annotations.sqldelete; импорт javax.persistence.Eentity; импорт javax.persistence.generatedValue; импорт javax.persistence.id; `klass` set deleted = 1, где id =?") открытый класс klass расширяет baseentity {@id @generatedValue Private Long ID; Приватное название строки; // setter and getter} @Entity @sqldelete (sql = "update` klass_test 'set adeted = 1, где id =? ") @Где (clause =" deleted = false ") открытый класс klasstest extends baseentity {@id @generatedValue Private Long Long ID; Приватное строковое имя;} Переписать Crudrepository
пакет com.mengyunzhi.springbootsamplecode.softdelete.core; импорт org.springframework.data.jpa.repository.query; import org.springframework.data.Repository.crudrepository; import org.spramework.data.RepoStory.noreporishory; javax.transaction.transactional; import java.util.optional;/*** Применить мягкое удаление* по умолчанию @where (clause = "deleted = 0") приведет к исключению ObjectNotfound, когда связанный запрос выполняется внутри Hibernate* Переосмысление интерфейса здесь* Ссылка: ссылка:: Ссылка:: Ссылка: Ссылка: Ссылка: Ссылка: Ссылка: Ссылка: Ссылка: Ссылка: Ссылка: Ссылка: Ссылка на интерфейс. https://stackoverflow.com/questions/19323557/handling-soft-deletes-with-spring-jpa/22202469 * @author Mengyunzhi Software Development Team of Hebei University of Technology*/@NoRepositoryBeanpublic interface SoftDeleteCrudRepository<T, ID> extends CrudRepository<T, ID> { @Override @Transactional @Query ("Выберите e из #{ #entityname} e, где e.id =? 1 и e.deleted = false") необязательно <t> findbyid (id id); @Override @transactional default boolean exactsbyid (id id) {return findbyid (id) .ispresent (); } @Override @TransActional @Query ("Выберите e из #{ #entityname} e, где e.deleted = false") итерабильный <t> findall (); @Override @TransActional @Query («Выберите e из #{ #entityname} e, где e.id in? 1 и e.deleted = false») итерабильный <t> findallbyid (iterable <id> ids); @Override @Transactional @Query ("Выберите count (e) из #{ #entityname} e, где e.deleted = false") long count ();} Создайте новый класс склада
Унаследование весеннего сухонеспозиции.
/*** class* @author panjie*/public interface klassrepository Extends SoftDeleteCrudRepository <Klass, long> {} Публичный интерфейс klasstestrepository расширяет SoftdeleteCrudRepository <klasstest, long> {} Public Interface TeacherRepository расширяет Crudrepository <Учитель, Long> {} тест
пакет com.mengyunzhi.springbootsamplecode.softdelete.repository; import com.mengyunzhi.springbootsamplecode.softdelete.entity.klass; импорт com.mengyunzhi.springbootsamplecode.softdelete.entity.entity.entity.entity. com.mengyunzhi.springbootsamplecode.softdelete.entity.teacher; импорт org.assertj.core.api.assertions; импорт org.junit.test; импорт org.junit.runner.runwith; import org.slf4j.logger; import org.lg.slggercy; org.springframework.beans.factory.annotation.autowired; import org.springframework.boot.test.context.springboottest; импорт org.springframework.orm.jpa.jpaobjectretrevalfailurexception; импорт org.spramework.test.contextrivexexcepptexception; импорт org.spramework.test.context.s. java.util.list; import java.util.optional;/** * @author panjie */@springboottest@runwith (springrunner.class) Открытый класс Учительрепоситирингттт {private final Static Logger logger = loggerfactory.getLogger (учительрепозиторитория .class); @Autowired klassrepository klassrepository; @Autowired klasstestrepository klasstestrepository; @Autowired Учительрепоситория Учительрепоситория; @Test public void findbyid () {logger.info («Создать нового учителя с Klass и Klasstest»); Klass klass = new klass (); klassrepository.save (klass); Klasstest klasstest = new klasstest (); klasstestrepository.save (klasstest); Учитель учителя = новый учитель (); Учитель.setklass (klass); Учитель.setklasstest (klasstest); Учительрепоситирий.save (учитель); logger.info («Ищите учителя, утверждают, что сущность была найдена, и никакого исключения не произошло»); Необязательный <учитель> учительнист -преподаватель = учительрепоситорий.findbyid (учитель.getid ()); Assertions.assertThat (учительнистка logger.info («Удалить связанный klass, затем посмотрите на сущность учителя, утверждают, что сущность была обнаружена, не было исключения. Утверждайте, что в субъекте учителя все еще есть удаленная сущность Klass»); klassrepository.deleteByid (klass.getid ()); Учительский OpenOptional = учительрепоситория.findbyId (учитель.getid ()); Assertions.assertThat (учительнистка Assertions.assertthat (учительница -офуции. Get (). GetKlass (). GetId ()). Isequalto (klass.getid ()); logger.info («Посмотрите на список учителей, никаких исключений не было. Утверждайте, что в предприятии преподавателя есть удаленная запись объекта Klass»); List <bestire> Учительский список = (List <bestive>) Учительрепоситория.findall (); для (учитель учителя1: учительница) {assertions.assertthat (учитель1.getklass (). getId ()). isequalto (klass.getid ()); } logger.info ("Удалить связанный klasstest, затем посмотрите на сущность учителя, утверждают, что удаленного Klasstest был найден"); klasstestrepository.deletebyid (klasstest.getid ()); Учительский OpenOptional = учительрепоситория.findbyId (учитель.getid ()); Assertions.assertThat (учительнистка Assertions.assertthat (учительническая доклада.get (). Getklasstest (). GetId ()). Isequalto (klasstest.getid ()); logger.info («Посмотрите список учителей снова, утверждают, что JpaobjectretievalfailureException произойдет (исключение EntityNotFound будет завоевано, инкапсулировано и брошено)") ")"); ");"); Логический уловкий разум = false; try {учительрепоситорий.findall (); } catch (jpaobjectretievalfailureException e) {catchException = true; } Assertions.AssertThat (chaterException) .istRue (); }} Суммировать
При использовании по умолчанию @sqldelete и @where Annotation данные JPA могут хорошо обрабатывать метод FindByID (), но он не может хорошо обрабатывать метод findall (). Здесь мы реализовали метод переписывания метода Crunrepository. Когда мы будем проводить основные запросы, мы используем наш индивидуальный метод для добавления deleted = true. Когда JPA проводит запрос ассоциации, поскольку мы не устанавливаем аннотацию @Where, все данные будут запрошены, тем самым избегая исключения, которое иногда возникает, когда выполняется запрос Foundall ().
В этой статье мы приводим только какой -то пример кода.
Если вам нужен полный код, нажмите: https://github.com/mengyunzhi/springbootsamplecode/tree/master/softdelete.
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.