V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
dcsuibian
V2EX  ›  问与答

Spring Boot JPA 在执行查询操作时发送了 update 语句?

  •  
  •   dcsuibian · 2022-03-06 15:47:33 +08:00 · 1076 次点击
    这是一个创建于 753 天前的主题,其中的信息可能已经有所发展或是发生改变。

    单张用户表,禁止重名,因此会在新增用户和改名时校验一下。

    因此有了下面的代码,在 save 操作之前进行一下 findByName 查询操作。如果存在同名用户,应该在下一个判断语句处抛出异常。而实际上在 findByName 这一句就抛出异常了。

    image-20220306153443675

    查看具体的 sql 执行结果发现,在执行 findByName 时,Hibernate 先发送了一条 update 语句,直接改掉了对应记录。

    image-20220306153544442

    网上查了一下,似乎是缓存的问题,但并不熟悉 Hibernate ,也没有显式配置过缓存,想问下如何禁止这个行为?(就是不让它在查询的时候自己 update )

    OpenJDK 11

    Spring Boot 2.5.3

    3 条回复    2022-03-07 12:39:33 +08:00
    eggoxygen
        1
    eggoxygen  
       2022-03-06 19:21:52 +08:00 via iPhone
    不知道是不是 JPA 的坑,在我具体的场景当中对于这种查的我统一会写一个方法。并且标记事务为 readonly 。这样就不会出现这种情况。而且我猜你 findByName 当中的 user 对象已经是一个准备新增的对象并且有值了。有大佬也可以讲讲这种情况如何可以避免。之前用的都是 Mybatis ,感觉 JPA 坑有点点多。
    dddd1919
        2
    dddd1919  
       2022-03-07 09:07:55 +08:00   ❤️ 1
    首先 @Transactional 注解不支持 protected 方法,全部是查询的方法上没必要也不应该使用事务注解
    另外猜测 save 可能是发生在外部调用,如果外部还有声明事务的话,即使不用 save 方法,只要修改了 jpa 返回的对象,都会在事务执行完成后 update
    dcsuibian
        3
    dcsuibian  
    OP
       2022-03-07 12:39:33 +08:00
    @dddd1919 应该不是修改 JPA 对象的问题。我做了一个转换层,目前程序里从 JPA 直接读出来的是 PO 对象 UserPO ,而方法的 User 是把 UserPO 转换了下(可以认为是复制),所以没有改过 JPA 对象。

    另外感谢提醒,才知道不支持 protected 对象。之前 private 的时候 idea 会报错,没多想,以为是它自己 extends 我的类来着。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2493 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 16:02 · PVG 00:02 · LAX 09:02 · JFK 12:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.