代码之家  ›  专栏  ›  技术社区  ›  Andrei Vajna II

在将RepositoryRestResource与另一个存储库组合时使用事务

  •  0
  • Andrei Vajna II  · 技术社区  · 6 年前

    JpaRepository 注释为 @RepositoryRestResource :

    @RepositoryRestResource
    public interface ItemRepository extends JpaRepository<Item, UUID> { }
    

    每当数据库中发生更改时,我都要更新文件。我是用 RepositoryEventHandler

    @Component
    @RepositoryEventHandler
    public class ItemRepositoryEventHandler {
    
        @HandleAfterCreate
        @HandleAfterSave
        @HandleAfterDelete
        public void itemChanged(Item item) {
            writeToFile();
        }
    }
    

    我要做的是,如果在将内容写入文件时出现错误,则应回滚数据库。

    @Transactional 注释到 ItemRepository RepositoryRestResource 执行三个步骤:发出 BeforeXXX AfterXXX 事件。它只在持久化步骤中使用事务,而不是三者中的一个。

    因此,我看不到在整个操作中使用事务的方法,唯一的选择是不使用 @回购资源 ,但要手动实现web层,请使用跨两个存储库使用事务的服务。有更简单的方法吗?

    1 回复  |  直到 6 年前
        1
  •  0
  •   Cepr0    6 年前

    一种方法是使用自定义控制器和服务实现业务逻辑。但这种方式抵消了Spring数据REST的“优势”。

    另一种选择(在我看来,SDR更自然)是使用 published events from aggregate roots . 在这种情况下,您应该从 AbstractAggregateRoot 并实现一个将发布某些“事件”的方法。那么您将能够处理此事件(在 @EventListener )在保存实体的过程中在同一事务中。例如:

    @Entity
    public class Order extends AbstractAggregateRoot {
        //...
    
        public void registerItems(List<Item> items) {
            this.registerEvent(new RegisterItemsEvent(this, items));
        }
    }
    
    @Getter
    @RequiredArgsConstructor
    public class RegisterItemsEvent {
        private final Order order;
        private final List<Item> items;
    }
    
    @RequiredArgsConstructor
    @Component
    public class EventHandler {
    
        private final ItemRepo itemRepo;
    
        @EventListener
        @Transactional(propagation = MANDATORY)
        public void handleRegisterItemsEvent(RegisterItemsEvent e) {
            Order order = e.getOrder();
            List<Item> items = e.getItems();
    
            // update items with order - skipped...
    
            itemRepo.saveAll(items);
        }
    }
    

    用法示例:

    @Component
    @RepositoryEventHandler
    public class OrderEventHandler {
    
        @BeforeCreate
        public void handleOrderCreate(Order order) {
    
            // prepare a List of items - skipped...
    
            order.registerItems(items);        
        }
    }
    

    Order 然后它发出 RegisterItemsEvent handleRegisterItemsEvent 你的方法 EventHandler 在同一事务中保存准备好的项目(我们使用 propagation = MANDATORY @Transaction 用于确保事务存在的注释)。

    Domain event publication from aggregate roots

    更新的

    对于您的特定任务,您可以创建类 ItemChangedEvent :

    @Getter
    @RequiredArgsConstructor
    public class ItemChangedEvent {
        private final Item item;
    }
    

    实现方法 markAsChanged Item 实体:

    @Entity
    public class Item extends AbstractAggregateRoot {
        //...
    
        public void markAsChanged() {
            this.registerEvent(new ItemChangedEvent(this));
        }
    }
    

    item 更改,您将其标记为“已更改”:

    @Component
    @RepositoryEventHandler
    public class ItemRepositoryEventHandler {
    
        @BeforeCreate
        @BeforeSave
        @BeforeDelete
        public void itemChanged(Item item) {
            item.markAsChanged();
        }
    }
    

    并将其写入 项目变更开发 同一事务中的处理程序:

    @Component
    public class EventHandler {
    
        @EventListener
        @Transactional(propagation = MANDATORY)
        public void handleItemChangedEvent(ItemChangedEvent e) {
            Item item = e.getItem();
            writeToFile(item);
        }
    }