3.4.5.5. 事务监听器
事务监听器旨在对事务生命周期事件做出响应。与实体监听器不同,它们不与何实体类型绑定,可以被每个事务调用。
监听器是一个Spring bean,它实现了 BeforeCommitTransactionListener
或 AfterCompleteTransactionListener
接口或者同时实现这两个接口。
- BeforeCommitTransactionListener
-
如果事务不是只读的,则在所有实体监听器之后,事务提交之前调用
beforeCommit()
方法。该方法接受当前持久化上下文中的实体集合和当前的EntityManager作为参数。监听器可用于执行涉及多个实体的复杂业务规则。在下面的例子中,
Order
实体的amount
属性必须根据订单中的discount
值计算,OrderLine
实体的price
和quantity
构成订单。@Component("demo_OrdersTransactionListener") public class OrdersTransactionListener implements BeforeCommitTransactionListener { @Inject private PersistenceTools persistenceTools; @Override public void beforeCommit(EntityManager entityManager, Collection<Entity> managedEntities) { // gather all orders affected by changes in the current transaction Set<Order> affectedOrders = new HashSet<>(); for (Entity entity : managedEntities) { // skip not modified entities if (!persistenceTools.isDirty(entity)) continue; if (entity instanceof Order) affectedOrders.add((Order) entity); else if (entity instanceof OrderLine) { Order order = ((OrderLine) entity).getOrder(); // a reference can be detached, so merge it into current persistence context affectedOrders.add(entityManager.merge(order)); } } // calculate amount for each affected order by its lines and discount for (Order order : affectedOrders) { BigDecimal amount = BigDecimal.ZERO; for (OrderLine orderLine : order.getOrderLines()) { if (!orderLine.isDeleted()) { amount = amount.add(orderLine.getPrice().multiply(orderLine.getQuantity())); } } BigDecimal discount = order.getDiscount().divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN); order.setAmount(amount.subtract(amount.multiply(discount))); } } }
- AfterCompleteTransactionListener
-
事务完成后调用
afterComplete()
方法。该方法接受一个参数,该参数表明事务是否已成功提交,以及已完成事务的持久化上下文中包含的已分离实体的集合。用法示例:
@Component("demo_OrdersTransactionListener") public class OrdersTransactionListener implements AfterCompleteTransactionListener { private Logger log = LoggerFactory.getLogger(OrdersTransactionListener.class); @Override public void afterComplete(boolean committed, Collection<Entity> detachedEntities) { if (!committed) return; for (Entity entity : detachedEntities) { if (entity instanceof Order) { log.info("Order: " + entity); } } } }