【问题标题】:Spring @Transactional method with save() command带有 save() 命令的 Spring @Transactional 方法
【发布时间】:2022-10-04 19:30:45
【问题描述】:

请问有人可以帮我吗?

我有使用 JPA 的经验,但没有使用 Spring 的经验,它隐藏了许多在 JPA 中可见的方面(例如 Hibernate 实现)。

我经常以这种模式(一个全局事务)在 JPA 中工作 - 我将尝试解释保存标题(method_A)及其项目(method_B) - 结果是发布全部或全部发布。我想通过 Spring 持久性来达到这种效果。我知道,带有@Transactional 注释的方法从外部获取会话(如果存在)。我的问题是,我认为,默认 Spring 存储库接口(例如 CrudRepository)的嵌套实现 save() 方法无论如何都会打开它自己的事务 - 这是我不想要的 - 只是我需要强制执行save() 方法从外部获取它。所以我不确定,如果只有 @Transactional 注释就足以强制这种行为。

这是我的 JPA 代码,在 Hibernate 中可以正常工作:


root_method() {
Transaction tx = session.beginTransaction();
  
  method_A(session);

tx.commit();
}

method_A(Session session) { 
  Header header = new Header();
  session.save(header);

  for (Item item : getJustAllocatedItems()) {
    item.setHeader(header);
    method_B(session, item);
  }
}

method_B(Session session, Item item) {
  session.save(item);
}

很抱歉,这不是纯 Java,但出于解释目的,我希望它就足够了。我将尝试以粗略的形式镜像 Spring 代码:


@Transactional
root_method() {
  // ... root_method should make overal transaction frame on background (I suppose, that root_method is not called from another method with @Transactional ann.)

  method_A();
}

@Transactional
method_A() { 
  Header header = new Header();
  headerRepository.save(header);

  for (Item item : getJustAllocatedItems()) {
    item.setHeader(header);
    method_B(item);
  }
}

@Transactional
method_B(Item item) {
  itemRepository.save(item);
}

...所以我不认为,存储库的 save() 方法(在 A 和 B 方法中)会从外部接收和使用事务 - 我是对的吗? - 如果是这样,请有人将我的 JPA 代码从第一部分解释为适当的 Spring 表示。非常感谢。

【问题讨论】:

    标签: spring transactions save


    【解决方案1】:

    如果您在没有事务的情况下调用存储库方法,则存储库 将创建交易:

    Creating new transaction with name [org...SimpleJpaRepository.save]
    Committing JPA transaction on EntityManager
    

    如果你使用事务注解(注意它应该在单独的服务中),那么保存将reuse事务:

    Creating new transaction with name [com...HeaderService.createHeader]
    Committing JPA transaction on EntityManager
    

    请注意,使用@Transactional 注释的数学应该属于不同的类(或者您应该使用setter 自动连接当前类)。然后Spring将能够使用代理。 Spring 将带有 @Transactional annoaions 的服务包装到代理中。

    启用 jpa 日志记录:

    logging.level.org.springframework.orm.jpa=DEBUG
    logging.level.org.springframework.transaction=DEBUG
    

    这是您的类层次结构的示例实现:

    @Service
    @AllArgsConstructor
    public class HeaderService {
        HeaderRepository headerRepository;
        ItemService itemService;
    
        @Transactional
        public void methodA() {
            Header header = new Header();
            headerRepository.save(header);
            for (Item item : getJustAllocatedItems()) {
                item.setHeader(header);
                itemService.methodB(item);
            }
        }
    }
    
    @Service
    @AllArgsConstructor
    public class ItemService {
        ItemRepository itemRepository;
        @Transactional
        void methodB(item) {
            itemRepository.save(item);
        }
    }
    
    public interface HeaderRepository extends CrudRepository<Header, Long> { }
    public interface ItemRepository extends CrudRepository<Item, Long> { }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-26
      • 2017-06-18
      • 1970-01-01
      • 2014-07-15
      • 2015-07-19
      • 2020-01-23
      • 2015-02-23
      相关资源
      最近更新 更多