この記事の開発環境:スプリングブート:2.0.3.Release + Java1.8
なぜするのか
ソフト削除:つまり、実際の削除操作は実行されません。エンティティ間にバインディング(外部キー)が存在するため、一部のデータを削除すると、他のデータが不完全になります。たとえば、コンピュータークラス1801の教師はZhang Sanです。この時点で、Zhang Sanを削除すると、Computer Class 1801を照会すると、Zhang Sanが存在しなくなったため、EntityNotFoundエラーを報告します。もちろん、外部キーの制約を備えたデータベースでは、Zhang Sanがクラス1801の教師である場合、Zhang Sanを直接削除し、拘束力のある例外を報告します。言い換えれば、Zhang Sanを直接削除する動作は実行できません。
しかし、時にはそれを削除する必要があります。たとえば、従業員が去り、従業員の管理で従業員を削除したいと考えています。ただし、従業員はデータテーブルに履歴があります。たとえば、2017年の第2学期のデータ構造はZhang Sanjiaoであることを記録しました。次に、制約の存在により、Zhang Sanを削除すると結合誤差が報告されます。言い換えれば、削除する必要があるが削除することはできないという恥ずかしさ。
これは、この記事に記載されているソフト削除を使用します。いわゆるソフト削除は、データテーブルのデータを実際に削除するのではなく、代わりにレコードにマークを削除するかどうかを追加することを意味します。
Spring JPAはソフト削除をサポートしています。この問題を解決するために、質の高い記事をもっと見つけることができます。一般的な手順は次のとおりです。1。@sqldeleteの追加( "update 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 3つの新しいエンティティを作成し、新しいBaseEntityの抽象クラスエンティティを作成します。 ClazzTest @Where(clause = "deleted = false")を使用するときに発生する例外を実証するために使用されます。
パッケージcom.mengyunzhi.springbootsamplecode.softdelete.entity; import javax.persistence.mappssuperclass; @mappsuperclaclasspublic abstract class beaseentity {private boolean deleted = fals; // setter and getter}パッケージcom.mengyunzhi.springbootsamplecode.softdelete.entity; Import org.hibernate.annotations.sqldelete; Import javax.persistence.entity; import javax.persistence.generatedValue; Import javax.persistence.id; `klass` set deleted = 1ここでid =?")パブリッククラスklassはbaseentity {@id @generatedValueプライベートLong id;プライベート文字列名; // setter and getter} @entity @sqldelete(sql = "update` klass_test` set deleted = 1 where id =? ") @where(clause =" deleted = false ")public class klasstestはbesentity {@id @generatedvalue private long id;プライベート文字列名;} Crudrepositoryを書き直します
パッケージcom.mengyunzhi.springbootsamplecode.softdelete.core; Import org.springframework.data.jpa.repository.query; import org.springframework.data.repository.crudrepository; Import org.springframework.data.data.data.Repotiontorybebebean javax.transaction.transactional; import java.util.optional;/*** apply soft delete* default @where(clause = "deleted = 0")の例外を引き起こします。 https://stackoverflow.com/questions/19323557/handling-soft-deletes-with-spring-jpa/22202469 * @author mengyunziソフトウェア開発チームhebei University of Technology */ @ @norebeanpublic Interface softdecrudRepositor {@override @transactional @query( "e.id =?1およびe.deleted = false")optional <t> findbyid(id id); @Override @Transactionalデフォルトのboolean exististsbyid(id){return findbyid(id).ispresent(); } @override @transactional @query( "e.deleted = false")iterable <t> findall(); @override @transactional @query( "e.d {#entityName} eを選択します。 @override @transactional @query( "select count(e)from#{#entityName} e where e.deleted = false")long count();}新しいウェアハウスクラスを作成します
SpringのCrudrepositoryを継承します。
/*** class* @author panjie*/public interface klassrepositoryはsoftdeletecrudrepository <klass、long> {}を拡張しますパブリックインターフェイスKlasstestrepositoryはsoftdeletecrudrepository <Klasstest、long> {}を拡張しますパブリックインターフェイスTeachErrePositoryはcrudrepositoryを拡張します<教師、long> {}テスト
パッケージcom.mengyunzhi.springbootsamplecode.softdelete.repository; Import com.mengyunzhi.springbootsamplecode.softdelete.entity.klass; Import com.mengyunzhi.springbootsamplecode.softdelete.entity.klasSttest; KlasSttest; com.mengyunzhi.springbootsamplecode.softdelete.entity.teacher; Import org.assertj.core.api.assertions; Import org.junit.test; import org.junit.runner.runwith; import org.slf4j.logger; import org.slf4j.logger; org.springframework.beans.factory.annotation.autowired; import org.springframework.boot.test.context.springboottest; Import org.springframework.orm.jpa.jpaobjectretrievalfailureexception; java.util.list; Import java.util.optional;/** * @author panjie */@springboottest@runwith(springrunner.class)public class teacherrepositorytest {private final static logger logger = loggeractory.getlogger(Teacherrepositytest.class); @autowired klassrepository klassrepository; @Autowired KlasStestRepository KlasStestRepository; @Autowired TeacherRepository Teacherrepository; @test public void findbyid(){logger.info( "KlassとKlasstestで新しい教師を作成する"); klass klass = new Klass(); klassrepository.save(klass); Klasstest Klasstest = new Klasstest(); klasstestrepository.save(klasstest);教師教師=新しい教師(); Teacher.setklass(klass); Teacher.setklasstest(Klasstest); TeachErrePository.save(教師); logger.info(「教師を探し、エンティティが見つかったことを主張し、例外が発生しなかった」); optional <teacher> teacheroptional = teacherrepository.findbyid(teacher.getId()); assertions.assertthat(teacheroptional.get())。isnotnull(); logger.info(「関連する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エンティティレコードがあると主張します」); List <Teacher> TeacherList =(list <teacher>)teacherrepository.findall(); for(Teacher Teacher1:TeacherList){assertions.assertthat(teacher1.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( "教師リストをもう一度調べて、jpaobjectretrievalfailureexceptionが発生すると主張します(entityNotFound例外がキャッチされ、カプセル化され、スローされます)例外"); boolean catchexception = false; try {teacherrepository.findall(); } catch(jpaobjectretrievalfailureexception e){catchexception = true; } assertions.assertthat(catchexception).istrue(); }}要約します
デフォルトの@SQLDELETEおよび@where Annotationを使用する場合、JPAデータはFindByID()メソッドを適切に処理できますが、FindAll()メソッドを適切に処理できません。ここでは、Crunrepositoryメソッドを書き換える方法を実装しました。基本的なクエリを実行するとき、カスタマイズされたメソッドを使用して削除= trueを追加します。 JPAが @where annotationを設定しないため、Associationクエリを実行すると、すべてのデータがクエリがクエリになり、Foundall()クエリが実行されたときに発生する例外を回避します。
この記事では、コードの例のみを示します。
完全なコードが必要な場合は、https://github.com/mengyunzhi/springbootsamplecode/tree/master/softdeleteをクリックしてください。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。