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

Micronaut JPA自定义更新方法在测试中不生效求助

嵌入式ID实体批量更新测试不生效问题排查

问题描述

在Micronaut项目中,定义了带嵌入式ID的ProductClientSystem实体,以及包含自定义批量更新方法的JpaRepository。接口调用这些更新方法功能正常,但在@MicronautTest测试用例中执行updateActive方法后,查询结果显示数据未更新。

实体代码

@AllArgsConstructor
@Getter
@Setter
@Entity
@Table(name = "product_client_systems")
@DynamicUpdate
public class ProductClientSystem implements Serializable {

    @EmbeddedId
    private ProductClientSystemId primaryKey;

    @ManyToOne(fetch =FetchType.LAZY)
    @JoinColumn(name = "client_id")
    @MapsId("clientSystemId")
    private ClientSystem clientSystem;

    @ManyToOne(fetch =FetchType.LAZY)
    @JoinColumn(name = "product_id")
    @MapsId("articleItemId")
    private Product product;

    @Column(name = "active" )
    private Boolean active = true;

    @Column(name = "created_at", updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdAt = new Date();
}

嵌入式ID代码

@Embeddable
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class ProductClientSystemId implements Serializable {

    @Column(name = "product_id")
    private Long articleItemId;
    @Column(name = "client_id")
    private Long clientSystemId;
}

Repository代码

@Repository
public interface ProductClientSystemRepository extends JpaRepository<ProductClientSystem, ProductClientSystemId> {

    List<ProductClientSystem> findByProductInList(List<Product> list);

    @Query("update ProductClientSystem set updatedAt=:updatedAt WHERE product in :list")
    void updateUpdatedAtByProductInList( Date updatedAt, List<Product> list);

    @Query("update ProductClientSystem o set o.active=:active WHERE o in :list")
    void updateActive(List<ProductClientSystem> list, boolean active);
}

测试代码

@MicronautTest
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
public class RTest {
    @Test
    void testRandom(){
        productClientSystemRepository.updateActive(articleCSNewUpdates,false);

        articleCSNewUpdates = productClientSystemRepository.findAll();

        assertFalse(articleCSNewUpdates.get(0).getActive()); // 此处报错

    }
}

排查原因及解决方法

1. 事务提交与持久化上下文刷新问题

批量更新的JPQL属于DML操作,不会自动刷新持久化上下文,测试中若未显式处理事务,更新可能未写入数据库。

  • 解决:在测试方法上添加@Transactional注解,确保更新在事务内执行并提交;或者在更新后调用productClientSystemRepository.flush()强制刷新到数据库。

2. 持久化上下文缓存导致脏读

如果articleCSNewUpdates是更新前从上下文加载的实例,更新后直接查询可能读取缓存中的旧数据。

  • 解决:更新后调用entityManager.clear()清空上下文,再执行查询;或者使用flush()确保更新写入数据库后再查询。

3. JPQL更新条件的实例识别问题

updateActive方法中用WHERE o in :list,如果传入的实体是离线状态(未被当前上下文托管),JPA无法正确匹配实例,导致无数据更新。

  • 解决:改用嵌入式ID列表作为更新条件,修改Repository方法:
@Query("update ProductClientSystem o set o.active=:active WHERE o.primaryKey in :ids")
void updateActive(List<ProductClientSystemId> ids, boolean active);

测试时传入实体的primaryKey列表而非实体实例列表。

4. 测试事务默认回滚行为

Micronaut测试默认会在方法结束后回滚事务,若在事务内查询能看到变化,但事务回滚后数据库无更新记录。

  • 解决:在测试方法上添加@Rollback(false)禁用回滚;或者开启新事务执行查询,确保读取的是数据库的最终状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 08:13:30