You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring使用QueryDSL自定义Repository更新测试失败如何解决

问题描述

我正在尝试使用集成QueryDSL的自定义Repository测试更新操作,但测试运行失败,数据未被更新。我尝试在调用Repository方法后执行flush操作,依旧没有生效。我刚接触Spring技术栈,推测该问题与EntityManager相关,但无法定位具体原因,相关代码与配置如下:

仓库代码

@Override
public Long updateNotice(String noticeId, Notice noticeInfo) {
    UpdateClause<JPAUpdateClause> updateBuilder = queryFactory.update(notice);

    if(StringUtils.isNotEmpty(noticeInfo.getTitle())) {
        updateBuilder.set(notice.title, noticeInfo.getTitle());
    }

    if(StringUtils.isNotEmpty(noticeInfo.getContents())) {
        updateBuilder.set(notice.contents, noticeInfo.getContents());
    }

    if(StringUtils.isNotEmpty(noticeInfo.getTheme())) {
        updateBuilder.set(notice.theme, noticeInfo.getTheme());
    }

    if (StringUtils.isNotEmpty(Integer.toString(noticeInfo.getState()))) {
        updateBuilder.set(notice.state, noticeInfo.getState());
    }

    if(StringUtils.isNotEmpty(noticeInfo.getLocation())) {
        updateBuilder.set(notice.location, noticeInfo.getLocation());
    }

    updateBuilder.set(notice.startDate, noticeInfo.getStartDate());
    updateBuilder.set(notice.endDate, noticeInfo.getEndDate());
    updateBuilder.set(notice.modiDate, LocalDateTime.now());

    Long count = updateBuilder
            .where(notice.noticeId.eq(noticeId))
            .execute();

    return count;
}

测试代码

@Test
public void updateNoticeTest() {

    //given
    Notice titleNotice = Notice.builder()
            .title("Update notice")
            .startDate(LocalDateTime.of(2021, 10, 11, 00, 00, 00))
            .endDate(LocalDateTime.of(2021, 12, 12, 00, 00, 00))
            .build();

    List<Notice> notices = noticeRepository.findAll();
    String id = notices.get(1).getNoticeId();
    Notice notice = notices.get(1);
    log.info(notice.toString());

    //when

    Long result = noticeRepository.updateNotice(id, titleNotice);
    noticeRepository.flush();

    //then
    Notice res = noticeRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("No such notice with id " + id));
    log.info(res.toString());
    assertThat(res.getTitle()).isEqualTo("Update notice");
}

测试配置

# Datasource settings
spring.datasource.url=jdbc:h2:mem:testdb;Mode=Oracle;DB_CLOSE_DELAY=-1
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=


# set jpa
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
#logging.level.org.hibernate.type.descriptor.sql=trace


# set log
logging.level.root=info

# set page option
# 1-based
spring.data.web.pageable.one-indexed-parameters=true
# page size = 10
spring.data.web.pageable.default-page-size=10
spring.data.web.pageable.max-page-size=1000

修复方案

核心问题1:缺少事务配置

QueryDSL的JPAUpdateClause.execute()更新操作必须在事务环境下运行,你的Repository更新方法和测试方法都没有加事务注解,更新操作不会提交到数据库,flush操作也不会生效。
此外Spring Data JPA测试默认开启事务自动回滚,添加事务注解后如果还是看不到更新结果,需要在测试方法上加@Rollback(value = false)关闭自动回滚。

核心问题2:状态判断逻辑存在空指针风险

StringUtils.isNotEmpty(Integer.toString(noticeInfo.getState()))逻辑有问题:如果noticeInfo的state为null,调用Integer.toString()会直接抛出空指针异常,即使当前测试用例未触发该问题,生产环境也会出现故障。

核心问题3:一级缓存导致查询到旧数据

JPA EntityManager默认开启一级缓存,你在测试开头调用findAll()已经把对应notice实体加载到了缓存中,后续调用findById()会直接从缓存读取旧数据,不会查询数据库最新值,即使更新操作成功也会拿到更新前的结果。

具体修改步骤

  1. 给Repository的updateNotice方法添加@Transactional注解,确保更新在事务内执行:
@Override
@Transactional
public Long updateNotice(String noticeId, Notice noticeInfo) {
    // 原有逻辑保持不变
}
  1. 修正state字段的判断逻辑:
// 替换原有判断
if (noticeInfo.getState() != null) {
    updateBuilder.set(notice.state, noticeInfo.getState());
}
  1. 调整测试代码:
  • 给测试方法添加@Transactional和@Rollback(false)注解
  • 在调用findById之前调用entityManager.clear()清空一级缓存,确保查询到数据库最新数据
  • 建议打印result返回值确认更新影响行数,如果返回值为0说明where条件未匹配到数据,需要检查传入的noticeId是否正确
  1. 可以打开配置文件中注释的SQL参数日志,确认更新语句的入参是否符合预期:
logging.level.org.hibernate.type.descriptor.sql=trace

内容的提问来源于stack exchange,提问作者jhlee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 00:06:07