【问题标题】:Spring JPA / Hibernate is calling full update before a special update using @Modifying and @QuerySpring JPA / Hibernate 在使用 @Modifying 和 @Query 的特殊更新之前调用完整更新
【发布时间】:2018-10-07 16:34:47
【问题描述】:

我有一个 Business 类的 spring 存储库:

public interface BusinessRepository extends JpaRepository<Business, String> {

这包括一种仅更新一个字段的简单方法(updateDatetime):

@Modifying
@Query("update Business business set business.updateDatetime = :updateDatetime where business.businessKey = :businessKey")
int setUpdateDatetimeForBusiness(@Param("updateDatetime") String updateDatetime, @Param("businessKey") String businessKey);

问题是当我调用这个方法时:

businessRepository.setUpdateDatetimeForBusiness(business.getUpdateDatetime(), business.getBusinessKey());

日志显示如下:

Hibernate: update business set name=?, timezone=?, updatedatetime=? where business_id=?
Hibernate: update business set updatedatetime=? where business_id=?

该方法正在调用实体的完整更新,然后调用我的更新。我应该改变什么来调用第二次更新?

【问题讨论】:

  • 能否贴出调用该方法的代码?
  • 在事务中对持久实体所做的更新将在事务结束时自动刷新。所以我猜你已经在事务中加载和修改(设置 updateDateTime)持久实体。当您的事务方法返回时,实体管理器会刷新更改。

标签: java spring spring-data spring-data-jpa


【解决方案1】:
@Query(value="update something", nativeQuery=true)

nativeQuery=true尝试添加这个


更新

抱歉没有仔细阅读问题。

由于您提供的炎症,我无法找出问题所在。但我确实有 给你的建议。

EntityManager 管理的实体可以自动持久化到数据库中,你登录Hibernate: update business set name=?, timezone=?, updatedatetime=? where business_id=? 好像更新了所有字段?如果是这样,更新更可能由EntityManager 调用。

您可以将flushMode 更改为COMMIT 以查看是否会进行更改。 (仅用于测试问题是否是由EntityManager的自动更新引起的)
例如:spring.jpa.properties.org.hibernate.flushMode=COMMIT 在 Spring Boot 中。


我的测试代码:

服务:

import cn.eeemt.dao.TagRepository;
import cn.eeemt.entity.Tag;
import cn.eeemt.service.TagService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Optional;

@Service
public class TagServiceImpl implements TagService {

    @Resource
    private TagRepository tagRepository;

    @Override
    public void update(String newDescription) {
        Tag tag = step1(newDescription);
        step2(tag.getDescription(), tag.getId());
    }

    @Transactional
    public Tag step1(String newDescription) {
        Optional<Tag> byId = tagRepository.findById(1);
        Tag tag = byId.orElseThrow(RuntimeException::new);
        System.out.println(tag);
        tag.setDescription(newDescription);
        // tagRepository.save(byId.get());  // I did not update it!!!
        return tag;
    }

    private void step2(String description, Integer id) {
        tagRepository.updateSome(description, id);
    }
}  

存储库:

import cn.eeemt.entity.Tag;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

public interface TagRepository extends JpaRepository<Tag, Integer> {

    @Modifying
    @Transactional
    @Query("update Tag tag set tag.description = :description where tag.id = :id")
    void updateSome(@Param("description") String description, @Param("id") int id);
}

spring.jpa.properties.org.hibernate.flushMode=ALWAYS

日志看起来像:

标签{id=1,名称='ffadsfasd',描述='dasfadsg',文章=[]}
休眠:更新标签集描述=?,名称=? id=?
休眠:更新标签集描述=? id=?

spring.jpa.properties.org.hibernate.flushMode=COMMIT

日志看起来像:

标签{id=1, name='ffadsfasd', description='dasfadsgaaer',articles=[]}
休眠:更新标签集描述=? id=?


如果问题是我上面所说的,除非适合您的情况,否则更改flushMode 不是一个好主意。你最好重构你的代码以获得更好的设计。


信息可能对您有所帮助:

【讨论】:

  • 如果 OP 想使用 JPQL 怎么办?这与手头的问题有什么关系?
猜你喜欢
  • 2017-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-14
  • 2020-05-09
  • 1970-01-01
  • 1970-01-01
  • 2021-03-31
相关资源
最近更新 更多