【发布时间】:2011-09-14 19:43:00
【问题描述】:
我正在使用 JPA EntityListener 执行一些额外的审计工作,并使用 @Configurable 将 Spring 管理的 AuditService 注入到我的 AuditEntryListener 中。 AuditService 生成一组 AuditEntry 对象。 AuditService 本身是一个单例范围的 bean,我想将所有 AuditEntry 对象收集在一个公共键下,然后可以由最外层的服务层访问(调用持久调用的那个又触发了 EntityListener)。
我正在考虑在事务开始时使用 Spring 的 TransactionSynchronizationManager 设置特定的事务名称(使用 UID() 或其他一些唯一策略),然后使用该名称作为 AuditService 中的键,这将允许我对在该事务中创建的所有 AuditEntry 对象进行分组。
混合使用声明式和程序化事务管理是否有潜在的麻烦? (虽然我只是设置事务名称)。有没有更好的方法将生成的 AuditEntry 对象与当前事务相关联?这个解决方案确实对我有用,但鉴于 TransactionSynchronizationManager 不适合应用程序使用,我想确保我对它的使用不会导致一些不可预见的问题。
相关问题
最后,一个相关但不是立即相关的问题:我知道 JPA EntityListeners 的文档警告不要使用当前的 EntityManager,但如果我确实想使用它来区分对象与它的持久自我,我会安全吗在我的 preUpdate() 方法周围使用 @Transactional(propagation=REQUIRES_NEW) 注释?
原型代码:
服务类
@Transactional
public void create(MyEntity e) {
TransactionSynchronizationManager.setCurrentTransactionName(new UID().toString());
this.em.persist(e);
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
Set<AuditEntry> entries = auditService.getAuditEntries(TransactionSynchronizationManager.getCurrentTransactionName());
if(entries != null) {
for(AuditEntry entry : entries) {
//do some stuff....
LOG.info(entry.toString());
}
}
}
});
}
JPA 实体监听器
@Configurable
public class AuditEntryListener {
@Autowired
private AuditService service;
@PreUpdate
public void preUpdate(Object entity) {
service.auditUpdate(TransactionSynchronizationManager.getCurrentTransactionName(), entity);
}
public void setService(AuditService service) {
this.service = service;
}
public AuditService getService() {
return service;
}
}
审计服务
@Service
public class AuditService {
private Map<String, Set<AuditEntry>> auditEntryMap = new HashMap<String, Set<AuditEntry>>();
public void auditUpdate(String key, Object entity) {
// do some audit work
// add audit entries to map
this.auditEntryMap.get(key).add(ae);
}
}
【问题讨论】:
标签: java spring jpa transactions synchronization