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
相关产品推荐
相关产品推荐

