Spring Data 存储库未从 save 方法返回更新的 @version

Wim*_*uwe 7 spring hibernate jpa spring-data

在 Spring Boot 1.3.0 应用程序中,我将 Spring Data JPA 与 Hibernate 结合使用。

我有这样的服务方法:

@Override
@Transactional(readOnly = false)
public BookDto updateBook(BookDto bookDto) {
        BookId id = new BookId(bookDto.getId());
        if (!exists(id)) {
            throw new EntityNotFoundException("Unable to find a book with id " + bookDto.getId());
        }
        return convertToDto(bookRepository.save(bookDto.convertToBook()));
    }
Run Code Online (Sandbox Code Playgroud)

在我的实体中,我有一个 @Version 字段:

@Version
private long version;
Run Code Online (Sandbox Code Playgroud)

(带有 getter 和 setter),我的 DTO 中也有这个(DTO 上没有 @Version 注释)。

从调用中返回的“Book”实体bookRepository.save()仍然具有version = 0,而不是1如预期的那样。当我之后在存储库上执行操作时findAll,版本更新得很好。这可能是什么原因?

pre*_*mar 5

由于它是一个事务,提交是在 return 语句之后发生的。在这种情况下,提交事务时更改将保留在数据库中。由于您没有显式刷新,更改仅在提交后反映在数据库中。在提交操作之前,您将实体的当前状态映射到 DTO。

解决方案1

如果您的 spring 存储库正在扩展 JpaRepository 那么您可以执行以下操作。

@Override
@Transactional(readOnly = false)
public BookDto updateBook(BookDto bookDto) {
    BookId id = new BookId(bookDto.getId());
    if (!exists(id)) {
        throw new EntityNotFoundException("Unable to find a book with id " + bookDto.getId());
    }
    return convertToDto(bookRepository.saveAndFlush(bookDto.convertToBook()));
}
Run Code Online (Sandbox Code Playgroud)

解决方案2

另一种无需显式刷新的解决方案:将实体的转换移至 updateBook() 方法之外的 dto 。使用其他一些辅助函数将实体映射到 dto。原因是因为如果没有显式刷新,实体在提交操作后会与数据库同步。但是您在提交事务之前将它们映射到 DTO。因此,将实体移动到 DTO 映射到某个映射器类或在服务层中进行。

@Override
@Transactional(readOnly = false)
public BookEntity updateBook(BookDto bookDto) {
    BookId id = new BookId(bookDto.getId());
    if (!exists(id)) {
        throw new EntityNotFoundException("Unable to find a book with id " + bookDto.getId());
    }
    return bookRepository.save(bookDto.convertToBook());
}

// call this method to map book entity to dto
public BookDTO mapToDTO(BookEntity){
    return bookDTO;
}
Run Code Online (Sandbox Code Playgroud)