El entorno de desarrollo de este artículo: Spring-Boot: 2.0.3. Release + Java1.8
Por qué hacer
Deleción suave: es decir, no se realiza una operación de eliminación real. Debido a la existencia de vinculación (claves extranjeras) entre nuestras entidades, eliminar algunos datos conducirá a otros datos incompletos. Por ejemplo, el maestro en la clase de computación 1801 es Zhang San. En este momento, si eliminamos Zhang San, cuando consultamos la clase de computación 1801, ya que Zhang San ya no existe, informaremos el error de EntityNotFound. Por supuesto, en una base de datos con restricciones de clave extranjera, si Zhang San es un maestro en la clase 1801, entonces eliminaremos directamente Zhang San e informaremos una excepción vinculante. En otras palabras, no se puede ejecutar el comportamiento de eliminar directamente a Zhang San.
Pero a veces, tenemos la necesidad de eliminarlo. Por ejemplo, un empleado se va y luego queremos eliminar al empleado en la gestión de los empleados. Sin embargo: el empleado tiene un historial en la tabla de datos. Por ejemplo, registramos que la estructura de datos del segundo semestre de 2017 era Zhang Sanjiao. Luego, debido a la existencia de restricciones, se informará un error de enlace al eliminar Zhang San. En otras palabras: la vergüenza de que se debe eliminar pero no se puede eliminar.
Esto utiliza la deleción suave mencionada en este artículo. La llamada eliminación suave significa que realmente no elimino los datos en la tabla de datos, sino que agrego una marca al registro de eliminarlo.
Spring JPA admite una eliminación suave, podemos encontrar más artículos con buena calidad para resolver este problema. Los pasos generales son: 1. Agregar @SqlDelete ("Actualizar xxxx set deleted = 1 where id = ?")。2.加入@Where(clause = "deleted = false") . Pero esta solución no es perfecta. Específicamente manifestado en:
Tomemos a Zhang San como maestro en la clase 1801 como ejemplo.
Después de agregar la anotación, de hecho podemos eliminar con éxito Zhang San. Después de la operación de eliminación, verificamos la tabla de datos y el registro de Zhang San todavía está allí. Pero en este momento, si hacemos all la consulta o page , recibiremos un error 500 EntiyNotFound . Esto se debe a que durante toda la consulta, JPA agrega automáticamente los parámetros de consulta en @Where . Debido a deleted = true de los datos asociados, una excepción de que no se encuentra la entidad asociada.
Pero el hecho es: aunque la entidad se elimina, todavía está allí y queremos aplicarla a la consulta de la asociación. No se espera que tenga una excepción 500 EntiyNotFound .
La solución de este artículo implementa:
Solución
Implementación
inicialización
Cree tres nuevas entidades: ClazzTest, Clazz, Teacher , y cree una nueva entidad de clase abstracta de base BaseEntity . Donde se usa ClazzTest para demostrar la excepción que ocurre cuando se usa @Where(clause = "deleted = false") .
paquete com.mengyunzhi.springbootsamplecode.softdelete.entity; import javax.persistence.MappedSuperClass; @MappedSuperClassPublic Abstract Class BaseEntity {private boolean deleted = false; // setter y getter} paquete com.mengyunzhi.springbootsamplecode.softdelete.entity; importar org.hibernate.annotations.sqlDelete; import javax.persistence.entity; import javax.persistence.generatedValue; import javax.persistence.id;/*** class*/@entity@sqlDelEte (sqlet = " `Klass` set Deleted = 1 donde id =?") La clase pública KLass extiende BaseEntity {@ID @GeneratedValue Private Long ID; nombre de cadena privada; // setter y getter} @Entity @sqlDelete (sql = "actualizar` klass_test` set Deleted = 1 donde id =? ") @Where (clause =" deleted = false ") clase pública KlasStest extiende BaseEntity {@id @GeneratedValue ID de largo privado; nombre de cadena privada;} Reescribir crudRepository
paquete com.mengyunzhi.springbootsamplecode.softdelete.core; import org.springframework.data.jpa.repository.Query; importar org.springframework.data.repository.crudRepository; import javax.transaction.transactional; import java.util.optional;/*** Aplicar deletero suave* default @where (clause = "deleted = 0") causará una excepción de ObjectNotFound cuando una consulta asociada se realice dentro de Hibernate* redefine la interfaz aquí* Referencia:: Referencia:: https://stackoverflow.com/Questions/19323557/handling-soft-deletes-with-spring-jpa/22202469 * @author Mengyunzhi Desarrollo de software Equipo de Hebei University of Technology */ @norePosyoryBeanPeanPublic Interface SoftDeletecrudRepository <t, Id> Extends CRUDREP @Override @Transactional @Query ("Seleccione E de #{ #EntityName} e donde e.id =? 1 y e.deleted = false") opcional <t> findByid (id id); @Override @Transactional Default boolean existyid (id id) {return findById (id) .IsPresent (); } @Override @Transactional @Query ("Seleccione E de #{ #EntityName} E Where E.Deleted = False") ITerable <T> findall (); @Override @Transactional @Query ("Seleccione E de #{ #EntityName} e donde e.id in? 1 y e.deleted = false") ITerable <T> findallById (ITerable <DID> ids); @Override @Transactional @Query ("Seleccione Count (E) de #{ #EntityName} e Where E.Deleted = False") Long Count ();} Crea una nueva clase de almacén
Heredando el crudRepository de Spring.
/*** clase* @Author Panjie*/Public Interface KLassRepository extiende SoftDeletecrudRepository <klass, long> {} interfaz pública klasstreSpository extiende SoftDeletecrudRepository <KlasStest, Long> {} Interfaz pública TeacherRepository extiende CrudrePository <Maestro, Long> {} prueba
paquete com.mengyunzhi.springbootsamplecode.softdelete.repository; import com.mengyunzhi.springbootsamplecode.softdelete.entity.klass; import Com.mengyunzhi.springbootsamplecode.softdelete.entity.klasstest; importar; import com.mengyunzhi.springbootsamplecode.softdelete.entity.teacher; import org.assertj.core.api.assertions; import org.junit.test; import org.junit.runner.runwith; import og.slf4j.logger; import org.slf4j.logger factory; org.springframework.beans.factory.annotation.aUtowired; import org.springframework.boot.test.context.springboottest; import org.springframework.orm.jpa.jpaobjectrievalfailureException; import org.springframework.test.conteTontext.Junit.springenner; java.util.list; import java.util.optional;/** * @author Panjie */@springboottest@runwith (springrunner.class) clase pública enseñerRepositoryTest {private final estático logger logger = loggerFactory.getLogger (maestroRepositoryTest.class); @AutoWired KLassRepository KLassRepository; @AUtowired KlasstreSpository KlasStestRepository; @AUtowired TeacherRepository TeacherRepository; @Test public void findByid () {logger.info ("Crea un nuevo maestro con Klass y Klasstest"); Klass klass = new Klass (); KLassRepository.save (Klass); Klasstest klasstest = new KlasStest (); klasstestrepository.save (klasstest); Maestro maestro = nuevo maestro (); profesor.setklass (Klass); profesor.setklasstest (KlasSstest); TeacherRepository.save (maestro); logger.info ("Busque al maestro, afirme que se encontró la entidad y no ocurrió ninguna excepción"); Opcional <firector> profesorOptional = TeacherRepository.findbyid (maestro.getid ()); ASSERTIONS.AssertThat (profesorOptional.get ()). Isnotnull (); logger.info ("Eliminar el Klass asociado, luego buscar la entidad del maestro, afirmar que se encontró la entidad, no ocurrió una excepción. Afirmar que todavía hay una entidad Klass eliminada en la entidad docente"); kLassRepository.DeleteById (klass.getID ()); profesorOptional = TeacherRepository.FindByid (maestro.getid ()); ASSERTIONS.AssertThat (profesorOptional.get ()). Isnotnull (); ASSERTIONS.AssertTHAT (profesorOptional.get (). GetKlass (). GetId ()). Iequalto (klass.getId ()); logger.info ("Busque la lista de maestros, no se produjo una excepción. Afirmar que hay un registro de entidad Klass eliminado en la entidad del maestro"); Lista <firector> profesorList = (list <firector>) TeacherRepository.Findall (); para (maestro maestro1: profesorlist) {afirmations.assertThat (maestro1.getklass (). getId ()). Iequalto (klass.getID ()); } logger.info ("Elimine el Klasstest asociado, luego busque la entidad del maestro, afirme que se encontró el klasstest eliminado"); klasstestrepository.deleteById (klasstest.getid ()); profesorOptional = TeacherRepository.FindByid (maestro.getid ()); ASSERTIONS.AssertThat (profesorOptional.get ()). Isnotnull (); ASSERTIONS.AssertThat (profesorOptional.get (). GetKlasStest (). GetId ()). IEqualto (klasStest.getId ()); logger.info ("Busque la lista de maestros nuevamente, afirme que se producirá una JPAOBJectrievalFailureException (la excepción de EntityNotFound se atrapa, encapsula y se arroja) excepción"); Boolean CatchException = false; intente {TeacherRepository.Findall (); } Catch (JPAOBJectrievalFailureException e) {CatchException = true; } Afirmaciones.AssertThat (CatchException) .istrue (); }} Resumir
Cuando se usa la anotación predeterminada de @sqlDelete y @Where, los datos JPA pueden manejar bien el método findByid (), pero no maneja bien el método findAll (). Aquí, hemos implementado el método para reescribir el método CrunRepository. Cuando realizamos consultas básicas, utilizamos nuestro método personalizado para agregar eliminado = true. Cuando JPA realiza una consulta de asociación, ya que no establecemos la anotación de @Where, todos los datos se consultarán, evitando así la excepción que ocurre a veces cuando se realiza la consulta FoundAll ().
En este artículo, solo damos algún código de ejemplo.
Si necesita el código completo, haga clic en: https://github.com/mengyunzhi/springbootsamplecode/tree/master/softdelete.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.