【问题标题】:Spring Boot - caling transactional method from non-transactional cause updateSpring Boot - 从非事务性原因更新中调整事务性方法
【发布时间】:2018-06-21 07:34:17
【问题描述】:

我想知道我最近遇到的一个案例。假设我们有一个服务方法如下:

@Override
public User addUser(UUID organizationId, User user) {
    Organization organization = organizationRepository.findById(organizationId).orElseThrow(IllegalArgumentException::new);
    user.setOrganization(organization);
    organization.getUsers().add(user);
    invitationService.deleteByUserEmail(user.getEmail());
    return user;
}

组织由存储库方法提供:

@Repository
public interface OrganizationRepository extends JpaRepository<Organization, UUID> {

    Optional<Organization> findById(UUID id);
}

添加用户仅因为存在invitationService.deleteByUserEmail(user.getEmail()); 而起作用。整个方法属于另一个服务,如下所示:

@Override
@Transactional
public void deleteByUserEmail(String userEmail) {
    invitationRepository.deleteByUserEmail(userEmail);
}

我不确定我是否正确理解添加用户的工作原理。根据 Hibernate Docs,只有当实体处于托管状态并且更新发生在单个事务中时,才会发生自动更新。如果我的推理是正确的,则会发生以下步骤:

  1. 当请求到达并到达控制器时,实体管理器(休眠会话)将附加到当前线程。 (?)
  2. 处理请求的控制器方法,调用organizationService.addUser方法
  3. OrganizationfindById 方法获取,该方法默认为事务性和只读的(根据 SimpleJpaRepository 实现)。此事务在此之后关闭,但绑定到它的实体管理器仍在运行,并且组织实体仍然受管理。
  4. 更新发生
  5. invitationService.deleteByUserEmail(user.getEmail()); 被调用。因为它是事务方法,所以开始了事务。发生删除,提交事务并将所有更改刷新到数据库中,即使是在组织实体中所做的更改。

是否有可能尽管 addUser 方法是非事务性

【问题讨论】:

标签: java hibernate spring-boot transactions entity


【解决方案1】:

在其中一个配置类上,您可能注册了特殊的过滤器,这些过滤器基本上使会话/实体管理器在整个请求的生命周期内保持打开状态:

org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter

org.springframework.orm.hibernate5.support.OpenSessionInViewFilter

【讨论】:

  • 感谢您的帮助。因此,默认情况下,实体管理器具有 FlushMode.NEVER。在某处使用 @Transactional 方法,将设置 FlushMode.AUTO 并在事务提交时刷新所有实体更改。甚至这些都发生在交易开始之前。如果我错了,请纠正我。
  • 好吧,AUTO 应该让持久性提供程序在他觉得需要时刷新。例如,当某些实体处于持久性上下文中并且您执行使用其中一些实体的查询时,然后刷新将被触发。如果您希望始终仅在事务提交时调用刷新,请使用 COMMIT 刷新模式选项
猜你喜欢
  • 2011-05-19
  • 2020-06-21
  • 2015-09-01
  • 2010-12-08
  • 1970-01-01
  • 2012-01-01
  • 2023-03-20
  • 2021-02-28
相关资源
最近更新 更多