Hi
In the project I’m working on there are a lot of services, and for quite some of them I would like to be able to call the methods either:
- through joining the current transaction (while being in a
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
call stack) - or open a new transaction (while being in a
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
call stack)
Knowing that UI is always opening a new transaction through DataManager
, so it is not an issue there.
Let’s see an example.
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void afterCommit(EntityChangedEvent<Customer, UUID> event) {
if (enableCommitTriggers) {
Id<Customer, UUID> entityId = event.getEntityId();
if (event.getType() != EntityChangedEvent.Type.DELETED) {
commentTemplateProcessorService.updateCustomerDocumentCommentsForDeliveryById(List.of(event.getEntityId()));
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void beforeCommit(EntityChangedEvent<Customer, UUID> event) {
if (enableCommitTriggers) {
Id<Customer, UUID> entityId = event.getEntityId();
if (event.getType() != EntityChangedEvent.Type.DELETED) {
commentTemplateProcessorService.updateCustomerDocumentCommentsForDeliveryById(List.of(event.getEntityId()));
[...]
Wanting the method updateCustomerDocumentCommentsForDeliveryById
call to work in both cases, I came with this design.
@Inject
private ExtTransactionalDataManager txDm;
@Override
public int updateCustomerDocumentCommentsForDeliveryById(List<Id<Customer, UUID>> ids) {
List<Customer> customers = txDm.load(Customer.class)
.view(View.LOCAL)
.ids(Ids.getValues(ids))
[...]
ExtTransactionalDataManager
is checking whether there is an open transaction, then join it or create a new one if none exists.
public class ExtTransactionalDataManager extends TransactionalDataManagerBean {
@Override
public <E extends Entity<K>, K> FluentLoader<E, K> load(Class<E> entityClass) {
return !isInTransaction(entityClass)
? dataManager.load(entityClass)
: super.load(entityClass);
}
protected boolean isInTransaction(Class<?> cls) {
MetaClass metaClass = metadata.getClassNN(cls);
return isInTransaction(metaClass);
}
protected boolean isInTransaction(MetaClass metaClass) {
String storeName = metadata.getTools().getStoreName(metaClass);
return isStoreInTransaction(storeName);
}
protected boolean isStoreInTransaction(String storeName) {
try {
if (storeName != null) {
persistence.getEntityManager(storeName);
} else {
persistence.getEntityManager();
}
return true;
} catch (IllegalStateException x) {
return false;
}
}
I’m not fond of that because creating an EntityManager
just for checking is probably hitting the perf. Initially I was using persistence.isInTransaction()
but I found out it does not work in all cases to know if there is actually an open transaction.
So I would be glad to know how others might have adressed this point.
Regards
Michael