3.4.5.5. 事务监听器

事务监听器旨在对事务生命周期事件做出响应。与实体监听器不同,它们不与何实体类型绑定,可以被每个事务调用。

监听器是一个Spring bean,它实现了 BeforeCommitTransactionListenerAfterCompleteTransactionListener 接口或者同时实现这两个接口。

BeforeCommitTransactionListener

如果事务不是只读的,则在所有实体监听器之后,事务提交之前调用 beforeCommit() 方法。该方法接受当前持久化上下文中的实体集合和当前的EntityManager作为参数。

监听器可用于执行涉及多个实体的复杂业务规则。在下面的例子中,Order 实体的 amount 属性必须根据订单中的 discount 值计算,OrderLine 实体的 pricequantity 构成订单。

  1. @Component("demo_OrdersTransactionListener")
  2. public class OrdersTransactionListener implements BeforeCommitTransactionListener {
  3. @Inject
  4. private PersistenceTools persistenceTools;
  5. @Override
  6. public void beforeCommit(EntityManager entityManager, Collection<Entity> managedEntities) {
  7. // gather all orders affected by changes in the current transaction
  8. Set<Order> affectedOrders = new HashSet<>();
  9. for (Entity entity : managedEntities) {
  10. // skip not modified entities
  11. if (!persistenceTools.isDirty(entity))
  12. continue;
  13. if (entity instanceof Order)
  14. affectedOrders.add((Order) entity);
  15. else if (entity instanceof OrderLine) {
  16. Order order = ((OrderLine) entity).getOrder();
  17. // a reference can be detached, so merge it into current persistence context
  18. affectedOrders.add(entityManager.merge(order));
  19. }
  20. }
  21. // calculate amount for each affected order by its lines and discount
  22. for (Order order : affectedOrders) {
  23. BigDecimal amount = BigDecimal.ZERO;
  24. for (OrderLine orderLine : order.getOrderLines()) {
  25. if (!orderLine.isDeleted()) {
  26. amount = amount.add(orderLine.getPrice().multiply(orderLine.getQuantity()));
  27. }
  28. }
  29. BigDecimal discount = order.getDiscount().divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN);
  30. order.setAmount(amount.subtract(amount.multiply(discount)));
  31. }
  32. }
  33. }

AfterCompleteTransactionListener

事务完成后调用 afterComplete() 方法。该方法接受一个参数,该参数表明事务是否已成功提交,以及已完成事务的持久化上下文中包含的已分离实体的集合。

用法示例:

  1. @Component("demo_OrdersTransactionListener")
  2. public class OrdersTransactionListener implements AfterCompleteTransactionListener {
  3. private Logger log = LoggerFactory.getLogger(OrdersTransactionListener.class);
  4. @Override
  5. public void afterComplete(boolean committed, Collection<Entity> detachedEntities) {
  6. if (!committed)
  7. return;
  8. for (Entity entity : detachedEntities) {
  9. if (entity instanceof Order) {
  10. log.info("Order: " + entity);
  11. }
  12. }
  13. }
  14. }