iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >解决spring-data-jpa 事物中修改属性自动更新update问题
  • 211
分享到

解决spring-data-jpa 事物中修改属性自动更新update问题

2024-04-02 19:04:59 211人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

问题还原 项目ORM层用的是spring-data-jpa,服务端接口实现的是树节点间的拖拽功能,测试环境联调发现异常问题,其中拖拽到目标目录后节点名称总会重名,重名规则是origi

问题还原

项目ORM层用的是spring-data-jpa,服务端接口实现的是树节点间的拖拽功能,测试环境联调发现异常问题,其中拖拽到目标目录后节点名称总会重名,重名规则是originName转化为originName(n)


    @Transactional(rollbackFor = Exception.class)
    public void move(MoveWorkSpaceDto moveWorkSpaceDto) {
        

        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操作,具体位置如下:

说明entity实体更新属性后,jpa自动执行了update属性,导致count判重始终大于0。

问题原因

jpa在hibernate上更进一步,我把单表的查询逻辑定义在Repository层的方法上,不用谢sql,简单明了,不曾想,忽略的hibernate的entity在session的3种状态。

  • 临时态,刚创建new的对象,还没有持久化,session缓存中也没有。
  • 游离态,已经持久化,但不在session缓存中。
  • 持久态,已经持久化,也在session缓存中。

问题原因明确,sourceEntity在持久态,修改属性自然会更新到数据库,判重查询已经更新了,查的还是自己,所以总是误认为有重复节点。

解决办法--隔离entity

避开session中缓存的sourceEntity的修改,创建新entity,修改临时态的entity,设置好属性后再调用save更新数据


    @Transactional(rollbackFor = Exception.class)
    public void move(MoveWorkSpaceDto moveWorkSpaceDto) {
        

        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中修改


    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修改


    @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修改属性。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: 解决spring-data-jpa 事物中修改属性自动更新update问题

本文链接: https://www.lsjlt.com/news/131976.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 解决spring-data-jpa 事物中修改属性自动更新update问题
    问题还原 项目orm层用的是spring-data-jpa,服务端接口实现的是树节点间的拖拽功能,测试环境联调发现异常问题,其中拖拽到目标目录后节点名称总会重名,重名规则是origi...
    99+
    2022-11-12
  • 如何解决spring-data-jpa事物中修改属性自动更新update问题
    小编给大家分享一下如何解决spring-data-jpa事物中修改属性自动更新update问题,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!问题还原项目orm层用...
    99+
    2023-06-20
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作