我有一个简单的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
事件。它仅在持久化步骤中使用事务,而不在所有三个步骤中使用一个事务。
因此,我看不到在整个操作中使用事务的方法,我看到的唯一选择是不使用@RepositoryRestResource
,而是手动实现Web层,然后使用在两个存储库中都采用事务的服务。有没有更简单的方法?
答案 0 :(得分:0)
一种方法是使用自定义控制器和服务来实现您的业务逻辑。但是这种方式抵消了Spring Data 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);
}
}
当SDR保存Order
时,它将发出RegisterItemsEvent
,这由您handleRegisterItemsEvent
的{{1}}方法处理,该方法将准备好的项目保存在同一笔交易中(我们使用{ EventHandler
注释的{1}}参数,以确保存在交易)。
其他信息:Domain event publication from aggregate roots
已更新
关于您的特定任务,您可以创建类propagation = MANDATORY
:
@Transaction
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();
}
}