激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

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

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

服務器之家 - 編程語言 - Java教程 - 解決spring-data-jpa 事物中修改屬性自動更新update問題

解決spring-data-jpa 事物中修改屬性自動更新update問題

2021-11-08 13:27南風nanfeng Java教程

這篇文章主要介紹了解決spring-data-jpa 事物中修改屬性自動更新update問題,具有很好的參考價值,希望對大家

問題還原

項目orm層用的是spring-data-jpa,服務端接口實現的是樹節點間的拖拽功能,測試環境聯調發現異常問題,其中拖拽到目標目錄后節點名稱總會重名,重名規則是originName轉化為originName(n)

?
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
@Transactional(rollbackFor = Exception.class)
public void move(MoveWorkSpaceDto moveWorkSpaceDto) {
    /***
     * 個人空間節點移動
     * 1、源節點移動到空目錄,那么目標父節點必傳,前置和后置節點都為空
     * 2、源節點移動到非空目錄:
     *   2.1、移動到目標目錄的第一個節點,那么后置節點必傳,前置節點為空
     *   2.2、移動到目標目錄的最后個節點,那么前置節點畢傳,后置節點為空
     *   2.3、移動到目標目錄的中間節點,那么前置節點和后置節點都要傳入
     * 3、節點拖動到目錄中,此時不知道目錄是否非空,前置后置節點都不傳,服務器追加到目錄的最后個節點
     */
 
    log.info(">>>MoveParams: [{}]", JSONObject.toJSONString(moveWorkSpaceDto));
    WorkSpaceEntity sourceEntity = workSpaceRepository.findById(moveWorkSpaceDto.getSourceWorkId()).orElse(null);
    if (sourceEntity == null) {
        throw new PublicsException("源工作空間節點不存在!");
    }
    WorkSpaceEntity parentEntity = workSpaceRepository.findById(moveWorkSpaceDto.getDestParentId()).orElse(null);
    if (parentEntity == null) {
        throw new PublicsException("目標父工作空間節點不存在!");
    }
    log.info(">>>>Noooooooo<<<<<");
    sourceEntity.setParentId(parentEntity.getId());
    log.info(">>>>UpdateNow<<<<<");
    Long cnt = workSpaceRepository.countAllByParentIdAndSpaceName(parentEntity.getId(), sourceEntity.getSpaceName());
    log.info("destParentId: [{}], spaceName: [{}], destCount: [{}]", parentEntity.getId(), sourceEntity.getSpaceName(), cnt);
    if (cnt > 0L) {
        String newName = RenameUtil.rename(sourceEntity.getSpaceName(), sourceEntity.getRunType(), cnt);
        sourceEntity.setSpaceName(newName);
    }
    if (moveWorkSpaceDto.getFrontWorkId() == null && moveWorkSpaceDto.getPostWorkId() == null) {
        List<WorkSpaceEntity> children = workSpaceRepository.findByParentIdOrderBySortIndexDesc(
                moveWorkSpaceDto.getDestParentId());
        if (CollectionUtils.isEmpty(children)) {
            sourceEntity.setSortIndex(sourceEntity.getId() * SORT_INDEX_STEP);
        } else {
            sourceEntity.setSortIndex(children.get(0).getSortIndex() + SORT_INDEX_STEP);
        }
    } else if (moveWorkSpaceDto.getFrontWorkId() != null && moveWorkSpaceDto.getPostWorkId() == null) {
        WorkSpaceEntity frontEntity = getFrontEntity(moveWorkSpaceDto);
        sourceEntity.setSortIndex(frontEntity.getSortIndex() + SORT_INDEX_STEP);
    } else if (moveWorkSpaceDto.getFrontWorkId() == null && moveWorkSpaceDto.getPostWorkId() != null) {
        WorkSpaceEntity postEntity = getPostEntity(moveWorkSpaceDto);
        sourceEntity.setSortIndex(postEntity.getSortIndex() - SORT_INDEX_STEP);
    } else {
        WorkSpaceEntity frontEntity = getFrontEntity(moveWorkSpaceDto);
        WorkSpaceEntity postEntity = getPostEntity(moveWorkSpaceDto);
        sourceEntity.setSortIndex((frontEntity.getSortIndex() + postEntity.getSortIndex()) / 2);
    }
    workSpaceRepository.save(sourceEntity);
}

排查后發現代碼邏輯正常,于是加日志定位,果然在更新項目前多了update操作,具體位置如下:

解決spring-data-jpa 事物中修改屬性自動更新update問題

說明entity實體更新屬性后,jpa自動執行了update屬性,導致count判重始終大于0。

問題原因

jpa在hibernate上更進一步,我把單表的查詢邏輯定義在Repository層的方法上,不用謝SQL,簡單明了,不曾想,忽略的hibernate的entity在session的3種狀態。

  • 臨時態,剛創建new的對象,還沒有持久化,session緩存中也沒有。
  • 游離態,已經持久化,但不在session緩存中。
  • 持久態,已經持久化,也在session緩存中。

問題原因明確,sourceEntity在持久態,修改屬性自然會更新到數據庫,判重查詢已經更新了,查的還是自己,所以總是誤認為有重復節點。

解決辦法--隔離entity

避開session中緩存的sourceEntity的修改,創建新entity,修改臨時態的entity,設置好屬性后再調用save更新數據

?
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
@Transactional(rollbackFor = Exception.class)
public void move(MoveWorkSpaceDto moveWorkSpaceDto) {
    /***
     * 個人空間節點移動
     * 1、源節點移動到空目錄,那么目標父節點必傳,前置和后置節點都為空
     * 2、源節點移動到非空目錄:
     *   2.1、移動到目標目錄的第一個節點,那么后置節點必傳,前置節點為空
     *   2.2、移動到目標目錄的最后個節點,那么前置節點畢傳,后置節點為空
     *   2.3、移動到目標目錄的中間節點,那么前置節點和后置節點都要傳入
     * 3、節點拖動到目錄中,此時不知道目錄是否非空,前置后置節點都不傳,服務器追加到目錄的最后個節點
     */
 
    log.info(">>>MoveParams: [{}]", JSONObject.toJSONString(moveWorkSpaceDto));
    WorkSpaceEntity sourceEntity = workSpaceRepository.findById(moveWorkSpaceDto.getSourceWorkId()).orElse(null);
    if (sourceEntity == null) {
        throw new PublicsException("源工作空間節點不存在!");
    }
    WorkSpaceEntity parentEntity = workSpaceRepository.findById(moveWorkSpaceDto.getDestParentId()).orElse(null);
    if (parentEntity == null) {
        throw new PublicsException("目標父工作空間節點不存在!");
    }
    WorkSpaceEntity updateEntity = new WorkSpaceEntity();
    BeanUtils.copyProperties(sourceEntity, updateEntity);
 
    Long cnt = workSpaceRepository.countByParentIdAndSpaceName(parentEntity.getId(), updateEntity.getSpaceName());
    log.info("destParentId: [{}], spaceName: [{}], destCount: [{}]", parentEntity.getId(), updateEntity.getSpaceName(), cnt);
    if (cnt > 0L) {
        String newName = RenameUtil.rename(updateEntity.getSpaceName(), updateEntity.getRunType(), cnt);
        updateEntity.setSpaceName(newName);
    }
    if (moveWorkSpaceDto.getFrontWorkId() == null && moveWorkSpaceDto.getPostWorkId() == null) {
        List<WorkSpaceEntity> children = workSpaceRepository.findByParentIdOrderBySortIndexDesc(
                moveWorkSpaceDto.getDestParentId());
        if (CollectionUtils.isEmpty(children)) {
            updateEntity.setSortIndex(updateEntity.getId() * SORT_INDEX_STEP);
        } else {
            updateEntity.setSortIndex(children.get(0).getSortIndex() + SORT_INDEX_STEP);
        }
    } else if (moveWorkSpaceDto.getFrontWorkId() != null && moveWorkSpaceDto.getPostWorkId() == null) {
        WorkSpaceEntity frontEntity = getFrontEntity(moveWorkSpaceDto);
        updateEntity.setSortIndex(frontEntity.getSortIndex() + SORT_INDEX_STEP);
    } else if (moveWorkSpaceDto.getFrontWorkId() == null && moveWorkSpaceDto.getPostWorkId() != null) {
        WorkSpaceEntity postEntity = getPostEntity(moveWorkSpaceDto);
        updateEntity.setSortIndex(postEntity.getSortIndex() - SORT_INDEX_STEP);
    } else {
        WorkSpaceEntity frontEntity = getFrontEntity(moveWorkSpaceDto);
        WorkSpaceEntity postEntity = getPostEntity(moveWorkSpaceDto);
        updateEntity.setSortIndex((frontEntity.getSortIndex() + postEntity.getSortIndex()) / 2);
    }
    updateEntity.setParentId(parentEntity.getId());
    workSpaceRepository.save(updateEntity);
}

場景復現

1、無事物的service中修改

?
1
2
3
4
5
6
7
public void test() {
    CronTaskEntity cronTaskEntity = cronTaskRepository.findById(18L).orElse(null);
    // 更新記錄
    cronTaskEntity.setUsername("魯班七號");
    CronTaskEntity newEntity = cronTaskRepository.findById(18L).orElse(null);
    Assert.isTrue(cronTaskEntity.getUsername().equals(newEntity.getUsername()), "查詢‘魯班七號'沒有更新啊");
}

運行后:

Caused by: java.lang.IllegalArgumentException: 查詢‘魯班七號'沒有更新啊

2、有事物中的service修改

?
1
2
3
4
5
6
7
8
@Transactional
public void test() {
    CronTaskEntity cronTaskEntity = cronTaskRepository.findById(18L).orElse(null);
    // 更新記錄
    cronTaskEntity.setUsername("魯班七號");
    CronTaskEntity newEntity = cronTaskRepository.findById(18L).orElse(null);
    Assert.isTrue(cronTaskEntity.getUsername().equals(newEntity.getUsername()), "查詢‘魯班七號'沒有更新啊");
}

運行后:

Hibernate: update `cron_task` set `createtime`=?, `updatetime`=?, `is_deleted`=?, `cron_expression`=?, `remark`=?, `staff_id`=?, `tag_id`=?, `username`=? where `id`=?

通過

由此可見,事物中會保存entity的緩存,修改entity屬性引起jpa自動update,因此避免誤操作,建議創建臨時態的entity修改屬性。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://www.jianshu.com/p/09d6c9f0e855

延伸 · 閱讀

精彩推薦
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
主站蜘蛛池模板: av在线免费网 | 久久久久久久.comav | 亚洲成年人免费网站 | 久久宗合色 | 成人午夜免费av | 成人午夜免费在线观看 | 99最新网址 | 国产午夜小视频 | 久久久国产精品网站 | 国产艳妇av视国产精选av一区 | 91高清视频 | 国产一区二区在线免费 | 国产日本在线播放 | 黄色一级片毛片 | 久色网站| 精品国产91一区二区三区 | 国产在线精品一区二区夜色 | 欧美精品一区自拍a毛片在线视频 | 欧美精品国产综合久久 | hd性videos意大利复古 | 日韩电影一区二区 | 成人在线视频网 | 国av在线 | v11av在线视频成人 | 九九热免费观看 | 亚洲第一成网站 | 视屏一区 | 亚洲欧洲av在线 | 久久精品一区二区三区四区五区 | 久久久久女人精品毛片 | 免费a级毛片永久免费 | 一道本不卡一区 | 久久亚洲精品国产 | 久久久久久久久日本理论电影 | 国产成人高清在线观看 | 超污视频在线看 | 中文字幕在线永久视频 | 成人福利网 | 日日摸夜夜添夜夜添牛牛 | 高清国产在线 | 国产一级毛片不卡 |