JpaRepository 缓存新创建的对象。如何刷新它?

2022-09-01 10:45:57

我有一个JpaRepository在Spring MVC应用程序中持久保存新创建的实体。此实体如下所示(非常简化):

@Entity
public class Translation {

    .....

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @ManyToOne(fetch = FetchType.LAZY)
    private Version version;

    ....

}

和版本实体:

@Entity
public class Version {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private long id;

    @Column(name = "name")
    private String name;

    @Column(name = "version_code")
    private long code;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "version", cascade = {CascadeType.ALL}, orphanRemoval = true)
    private Set<Translation> translations;

}

我创建了一个这样的翻译对象

            TranslationDTO t = new TranslationDTO();
            t.setText(translationText);
            ClientVersionDTO version = new ClientVersionDTO();
            version.setId(11);
            t.setVersion(version);

其中 11 是从一开始就存在于数据库中的版本。请注意,我没有为 ClientVersionDTO 设置 值。namecode

然后我有一个持久保存新对象的服务(我使用库将DTO转换为实体)dozer

@Service
@Transactional
public class TranslationsServiceImpl implements TranslationsService {
    @Override
    public Long create(TranslationDTO translationDTO) {
        Translation translation = translationsConverter.unconvert(translationDTO);
        Translation t = translationRepository.saveAndFlush(translation);

        Translation t2 = translationRepository.findOne(t.getId());

        // !!!! t2.getVersion() returns version where no values are set to 'code' and 'name'

        return t2.getId();
    }
}

请注意我的注释“t2.getVersion()返回没有值设置为'code'和'name'的版本” - 我期望这样当我从数据库获取数据时,我会直接从数据库中获得一个对象,并设置了值。但是,它们不是设置的。因此,基本上我作为对象得到的与输入参数中的对象相同。他们如何使对象重新失效?Versioncodenamet2.getVersion()translationDTO.getVersion()Version

UPDATE尝试将@Transactional移动到JpaRepository,但结果仍然相同。


答案 1

如果您使用的是休眠,这是预期的结果。当您调用并且一个接一个地调用时,它们会命中相同的Hibernate会话,该会话维护它所处理的所有对象的缓存。因此,第二个调用仅返回传递给第一个调用的对象。这两行中没有任何内容会强制 Hibernate 对实体的数据库进行查询。translationRepository.saveAndFlush(translation)translationRepository.findOne(t.getId())SELECTVersion

现在,JPA规范在接口上确实有一个方法。不幸的是,Spring Data JPA没有使用其接口公开此方法。如果此方法可用,则可以执行此操作,然后强制 JPA 提供程序将版本实体与数据库同步。refreshEntityManagerJpaRepositoryt = translationRepository.saveAndFlush(translation)versionRepository.refresh(t.getVersion())

实现此方法并不困难。只需从Spring Data JPA扩展类并自己实现该方法即可。有关详细信息,请参阅向所有 Spring Data JPA 存储库添加自定义行为SimpleJpaRepository

另一种方法是加载版本实体,就像在翻译上设置它之前一样。由于您可以在代码中对版本 ID 进行硬编码,因此您的版本似乎是静态的。因此,您可以将实体标记为 和(前者是特定于 Hibernate 的注释)。这样,就不应该在每次调用数据库时都命中数据库。versionRepository.findOne(version.getId())Version@Immutable@CacheableversionRepository.findOne(version.getId())


答案 2

推荐