一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - Java教程 - spring boot實現軟刪除的示例代碼

spring boot實現軟刪除的示例代碼

2021-05-13 11:17myskies Java教程

這篇文章主要介紹了spring boot實現軟刪除的示例代碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

本文開發環境:spring-boot:2.0.3.release + java1.8

why to do

軟刪除:即不進行真正的刪除操作。由于我們實體間的約束性(外鍵)的存在,刪除某些數據后,將導致其它的數據不完整。比如,計算機1801班的教師是張三,此時,我們如果把張三刪除掉,那么在查詢計算機1801班時,由于張三不存了,所以就會報entitynotfound的錯誤。當然了,在有外鍵約束的數據庫中,如果張三是1801班的教師,那么我們直接刪除張三將報一個約束性的異常。也就是說:直接刪除張三這個行為是無法執行的。

但有些時候,我們的確有刪除的需求。比如說,有個員工離職了,然后我們想在員工管理中刪除該員工。但是:該員工由于在數據表中存在歷史記錄。比如我們記錄了17年第二學期的數據結構是張三教的。那么,由于約束性的存在,刪除張三時就會報約束性錯誤。也就是說:出現了應該刪除,但卻刪除不了的尷尬。

這就用到了本文所提到的軟刪除,所謂軟刪除,就是說我并不真正的刪除數據表中的數據,而是在給這條記錄加一個是否刪除的標記。

spring jpa是支持軟刪除的,我們可以找到較多質量不錯的文章來解決這個問題。大體步驟為:1. 加入@sqldelete("update xxxx set deleted = 1 where id = ?")。2.加入@where(clause = "deleted = false")的注解。但這個解決方案并不完美。具體表現在:

我們還以張三是1801班的教師舉例。

加入注解后,我們的確是可以做到可以成功的刪除張三了,刪除操作后,我們查看數據表,張三的記錄的確也還在。但此時,如果我們進行all或是page查詢,將得到一個500 entiynotfound錯誤。這是由于在all查詢時,jpa自動加入了@where中的的查詢參數,由于關聯數據的deleted = true,進而發生了未找到關聯實體的異常。

但事實是:實體雖然被刪除,但實際在還在,我們想將其應用到關聯查詢中。并不希望其發生500 entiynotfound異常。

本文的方案實現了:

  1. 可以成功的實現軟刪除。
  2. 再進行關聯刪除時,不發生500 entiynotfound錯誤。

解決方案

  1. 即然500是由于注解@where(clause = "deleted = false")引起的,那么我們棄用該注解。
  2. 我們需要在查詢時,加入deleted = false的查詢。那么我們新建一個接口,并繼承jpa的crudrepository,然后重寫其查詢相關的方法。在重寫過程中,加入deleted = false的查詢條件。

實施

spring boot實現軟刪除的示例代碼

初始化

新建clazztest, clazz, teacher三個實體,新建baseentity抽象類實體。其中clazztest用于演示使用@where(clause = "deleted = false")注解時發生的異常。

?
1
2
3
4
5
6
7
8
9
package com.mengyunzhi.springbootsamplecode.softdelete.entity;
 
import javax.persistence.mappedsuperclass;
 
@mappedsuperclass
public abstract class baseentity {
  private boolean deleted = false;
  // setter and getter
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.mengyunzhi.springbootsamplecode.softdelete.entity;
 
import org.hibernate.annotations.sqldelete;
 
import javax.persistence.entity;
import javax.persistence.generatedvalue;
import javax.persistence.id;
 
/**
 * 班級
 */
@entity
@sqldelete(sql = "update `klass` set deleted = 1 where id = ?")
public class klass extends baseentity {
  @id
  @generatedvalue
  private long id;
  private string name;
  // setter and getter
}
?
1
2
3
4
5
6
7
8
@entity
@sqldelete(sql = "update `klass_test` set deleted = 1 where id = ?")
@where(clause = "deleted = false")
public class klasstest extends baseentity {
  @id @generatedvalue
  private long id;
  private string name;
}

重寫crudrepository

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.mengyunzhi.springbootsamplecode.softdelete.core;
 
 
import org.springframework.data.jpa.repository.query;
import org.springframework.data.repository.crudrepository;
import org.springframework.data.repository.norepositorybean;
 
import javax.transaction.transactional;
import java.util.optional;
 
/**
 * 應用軟刪除
 * 默認的@where(clause = "deleted = 0")會導致hibernate內部進行關聯查詢時,發生objectnotfound的異常
 * 在此重新定義接口
 * 參考:https://stackoverflow.com/questions/19323557/handling-soft-deletes-with-spring-jpa/22202469
 * @author 河北工業大學 夢云智軟件開發團隊
 */
@norepositorybean
public interface softdeletecrudrepository<t, id> extends crudrepository<t, id> {
  @override
  @transactional
  @query("select e from #{#entityname} e where e.id = ?1 and e.deleted = false")
  optional<t> findbyid(id id);
 
  @override
  @transactional
  default boolean existsbyid(id id) {
    return findbyid(id).ispresent();
  }
 
  @override
  @transactional
  @query("select e from #{#entityname} e where e.deleted = false")
  iterable<t> findall();
 
  @override
  @transactional
  @query("select e from #{#entityname} e where e.id in ?1 and e.deleted = false")
  iterable<t> findallbyid(iterable<id> ids);
 
  @override
  @transactional
  @query("select count(e) from #{#entityname} e where e.deleted = false")
  long count();
}

新建倉庫類

繼承spring的crudrepository。

?
1
2
3
4
5
6
/**
 * 班級
 * @author panjie
 */
public interface klassrepository extends softdeletecrudrepository<klass, long>{
}
?
1
2
public interface klasstestrepository extends softdeletecrudrepository<klasstest, long> {
}
?
1
2
public interface teacherrepository extends crudrepository<teacher, long> {
}

測試

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package com.mengyunzhi.springbootsamplecode.softdelete.repository;
 
import com.mengyunzhi.springbootsamplecode.softdelete.entity.klass;
import com.mengyunzhi.springbootsamplecode.softdelete.entity.klasstest;
import 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.loggerfactory;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.boot.test.context.springboottest;
import org.springframework.orm.jpa.jpaobjectretrievalfailureexception;
import org.springframework.test.context.junit4.springrunner;
 
import java.util.list;
import java.util.optional;
 
 
/**
 * @author panjie
 */
@springboottest
@runwith(springrunner.class)
public class teacherrepositorytest {
  private final static logger logger = loggerfactory.getlogger(teacherrepositorytest.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 teacher = new teacher();
    teacher.setklass(klass);
    teacher.setklasstest(klasstest);
    teacherrepository.save(teacher);
 
    logger.info("查找教師,斷言查找了實體,并且不發生異常");
    optional<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實體記錄");
    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注解時,jpa data能夠很好的處理findbyid()方法,但卻未能很好的處理findall()方法。在此,我們通過重寫crunrepository的方法,實現了,將進行基本的查詢時,使用我們自定義的加入了deleted = true的方法。而當jpa進行關聯查詢時,由于我們未設置@where注解,所以將查詢出所有的數據,進而避免了當進行findall()查詢時,有被刪除的關聯數據時而發生的異常。

本文中,我們只給了部分示例代碼。

如果你需要完整的代碼,請點擊:https://github.com/mengyunzhi/springbootsamplecode/tree/master/softdelete

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://segmentfault.com/a/1190000015459505

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 无码精品一区二区三区免费视频 | 国产精品美女久久久久 | 韩国靠逼 | 免费一看一级毛片人 | 男人懂得网站 | 风间由美理论片在线观看 | 国产91精品在线播放 | 美国69xxxx59| 国产午夜久久精品 | 欧美高清国产 | 91精品国产免费久久国语蜜臀 | avtt手机版| 亚洲国产情侣偷自在线二页 | 插得好爽| 无码任你躁久久久久久久 | 国产亚洲一区二区三区 | 欧美大陆日韩一区二区三区 | 2019nv天堂| 亚洲成在人线久久综合 | 草草视频人人爽 | 日韩精品一区二区三区老鸭窝 | 国产精品成人一区二区1 | 国产福利在线观看91精品 | 91制片厂制作传媒破解版免费 | www.四虎.com| 午夜性爽视频男人的天堂在线 | 歪歪动漫小说sss | 亚洲国产天堂 | 天天狠天天透天干天天怕处 | 欧美日韩中文字幕一区二区高清 | 涩色网站 | 变态女王麻麻小说在线阅读 | gay帅老头毛都白了 gayxxx视频 | 九色PORNY真实丨国产大胸 | 天天操天天舔 | 好女孩韩剧免费观看 | 搡60一70岁的老女人小说 | www.四虎网站 | 成年视频在线观看 | fc2免费人成在线 | 国产亚洲精品自在线亚洲情侣 |