Смешивание декларативных и программных транзакций со слушателями Spring и JPA

Я использую JPA EntityListener для выполнения некоторой дополнительной работы по аудиту и вставляю AuditService, управляемый Spring, в свой AuditEntryListener с помощью @Configurable. AuditService создает коллекцию объектов AuditEntry. AuditService сам по себе является bean-компонентом с одноэлементной областью видимости, и я хотел бы собрать все объекты AuditEntry под общим ключом, к которому затем может получить доступ самый внешний уровень службы (тот, который вызвал вызов persist, который, в свою очередь, запустил EntityListener).

Я собираюсь использовать TransactionSynchronizationManager Spring для установки определенного имени транзакции (с использованием UID () или какой-либо другой уникальной стратегии) ​​в начале транзакции,а затем используя это имя в качестве ключа в AuditService, что позволит мне сгруппировать все объекты AuditEntry, созданные в этой транзакции.

Может ли сочетание декларативного и программного управления транзакциями вызвать проблемы? (Хотя я не делаю ничего, кроме установки имени транзакции). Есть ли лучший способ связать сгенерированные объекты AuditEntry с текущей транзакцией? Это решение действительно работает для меня, но, учитывая, что TransactionSynchronizationManager не предназначен для использования в приложениях, я хотел бы убедиться, что мое его использование не вызовет некоторых непредвиденных проблем.

Связанный вопрос

Наконец, связанный, но не сразу уместный вопрос: я знаю, что документация для JPA EntityListeners предостерегает от использования текущего EntityManager, но если бы я действительно хотел использовать его для сравнения объекта с его постоянным самим собой, можно ли было бы безопасно использовать @Transactional ( распространение = REQUIRES_NEW) вокруг моего метода preUpdate ()?

Код прототипа:

Класс обслуживания

@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 EntityListener

@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;
}

}

AuditService

@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);
}

}
10
задан abalogh 14 June 2011 в 19:23
поделиться