【问题标题】:Test JpaRepository findById returns null for UUID测试 JpaRepository findById 为 UUID 返回 null
【发布时间】:2021-04-25 08:03:19
【问题描述】:

这里是春季新手,
我想测试存储库的findById() 方法,但即使它已保存(并存在)在数据库中,它也找不到该条目:

@DataJpaTest
class CustomerRepoIntegration {

    @Autowired
    CustomerRepo customerRepo;

    @Test
    @Transactional
    void findById() {
        UUID uuid = UUID.randomUUID();
        Customer customer = new Customer(uuid);
        customerRepo.save(customer);

        List<Customer> allCustomers = customerRepo.findAll();
        assertEquals(1, allCustomers.size());

        Optional<Customer> foundCustomer = customerRepo.findById(uuid);
        assertTrue(foundCustomer.isPresent());
    }
}

虽然第一个断言成功,但第二个断言失败:

Error:  Failures: 
Error:    CustomerRepoIntegration.findById:32 expected: <true> but was: <false>

其余代码:

// CustomerRepo.java
public interface CustomerRepo extends JpaRepository<Customer, UUID> {}
// Customer.java
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Customer implements Serializable {
    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(
            name = "UUID",
            strategy = "org.hibernate.id.UUIDGenerator"
    )
    private UUID id;
}

我也在这里做了一个复制回购:https://github.com/ofhouse/stackoverflow-65818312

【问题讨论】:

  • id由数据库生成。因此,您分配的 id 正在丢失。而是使用customer.getId() 再次找到它。将@Data@Entity 一起使用也是一个坏主意。 (见deinum.biz/2019-02-13-Lombok-Data-Ojects-Arent-Entities)。
  • 确实,自动生成的 id 是这里的问题。感谢您在一起使用 @Data@Entity 时提供的提示。很好的阅读,不知道这个!

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


【解决方案1】:

尝试使用

customerRepo.saveAndFlush(customer) 而不是save(customer)

此外,如果您配置了负责自动生成 id 的实体注释,则更好的办法是不要干扰此机制,创建您自己的 UUID 并初始化实体。 Hibernate 会自动为您完成。

为什么不呢?

Hibernate 有自己的机制,取决于带有@Id 注解的标记字段是否与EntityManager 合并或持久化实体(如果该字段为空或包含数据)。

而不是

UUID uuid = UUID.randomUUID();
Customer customer = new Customer(uuid);

你可以这样做

Customer customer = new Customer();

并在此处从实体的持久实例中获取 UUID:

var persistedCustomer = customerRepo.saveAndFlush(customer);
...
Optional<Customer> foundCustomer = customerRepo.findById(persistedCustomer.uuid);

【讨论】:

  • 是的,使用 saveAndFlush。尝试删除 @Transactional 注释也可以解决问题。
  • 刷新在查询之前会自动发生,因此在这里没有效果。删除@Transactional 是完全错误的,因为它会在完全不切实际的设置(没有事务)中运行测试,这也可能引发各种问题,最后会在表中留下数据,这会干扰未来的测试运行相同或其他测试。问题在于 UUID 的生成。
  • 非常感谢您在这里提供所有有用的答案和 cmets!关键是 UUID 被自动生成的值覆盖。使用修复更新了示例 repo:github.com/ofhouse/stackoverflow-65818312/commit/…
猜你喜欢
  • 2019-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-14
  • 2021-10-30
  • 1970-01-01
相关资源
最近更新 更多