Spring Boot JPA CrudRepository - 实体未附加到persistencecontext
Posted
技术标签:
【中文标题】Spring Boot JPA CrudRepository - 实体未附加到persistencecontext【英文标题】:Spring Boot JPA CrudRepository - entities are not attached to persistencecontext 【发布时间】:2020-09-29 01:33:34 【问题描述】:经过多年的 JEE,我目前正在实现我的第一个 Spring Boot 应用程序。
我想知道 JPA / Hibernate 的行为。在 JEE 中,一旦持久化或“找到”@Entity,对此实体的所有更改都会由 JPA 实现自动填充到数据库中,无需调用 persist()、flush() 等。
现在使用 CrudRepository 的更改只有在我明确调用 save() 时才会存储到数据库中。
我的 CrudRepository:
public interface UserAccountRepository extends CrudRepository<UserAccount, Long>
public Optional<UserAccount> findByEmail(String email);
public Optional<UserAccount> findByVerificationCode(String verificationCode);
示例代码:
public void updateUser(Long userId, String newName)
UserAccount userAccount = userAccountRepository.findById(userId)
.orElseThrow(() -> new NotFoundException("Userid not found"));
userAccount.setLastName(newName);
//Stop here in JEE
userAccountRepository.save(userAccount);
在 .setLastName 之后的 JEE 实现中,更改将由 Hibernate 持久保存到数据库中。在我的 spring-boot 服务中它不是。通常明确需要发出 .save() 任何想法为什么以及如何获得与 JEE 中相同的行为?
【问题讨论】:
【参考方案1】:实际上 Spring boot Repository 在后台使用 JPA 将实体持久化到数据库中。但我想解释一下幕后发生的事情。你知道有一个EntityManager
有一个持久性上下文。创建EntityManager
时,它将自己附加到当前TransactionManager
,以便当该事务提交该持久性上下文中的所有数据时,该持久性上下文中的所有数据将被提交到数据库,或者另一方面,当事务回滚该持久性上下文中的所有数据时,该持久性上下文中的所有数据将被提交回滚。在 Spring Repository 中,您可以看到没有显式的持久性上下文。此持久性上下文存在但在幕后工作,当findById
方法返回并向您提供实体时,该实体未附加到持久性上下文实际上此上下文在 findById 返回时关闭。
但是 Spring Repository 使所有这些过程对用户透明,因为它在幕后使用 EntityManager
和事务管理器。实际上是 Spring 的魔杖让你省略了所有这些样板代码。但是这种魔法并非没有任何缺点,在您的 updateUser
方法中,您没有打开并且您没有提交任何事务,但它们实际上在幕后打开并提交了两次,一次是当您调用 findById
方法时,它打开事务,获取数据并提交它。当您再次在此处保存数据时,事务打开,并且持久性上下文内容在事务提交时保存到数据库。想象一下,您的特殊方法中有一些事务处理,在这种情况下,您应该特别考虑一下。
【讨论】:
以上是关于Spring Boot JPA CrudRepository - 实体未附加到persistencecontext的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot(十五):spring boot+jpa+thymeleaf增删改查示例
[Spring Boot] Adding JPA and Spring Data JPA