Thank you once again. I don't doubt you're right that this would break the contract. I'm not trying to gets the specs revised, just trying to understand and find a clean way to get what I want. So here's what I have in mind:
My DAOs all inherit from a base DAO class that injects the persistence context like this:
Code:
@Repository
public abstract class GenericDao<T, ID extends Serializable> {
@PersistenceContext
private EntityManager entityManager;
public void persist( T entity ) {
entityManager.persist( entity );
}
}
So to setup a "clean slate" context and continue to use my DAOs, I have to change the context's entityManager (and JDBC connection to be complete, thanks for pointing that out). I don't think I can simply create a new entityManager in the callee: this won't change the fact that the caller's entityManager will already have been bound to the transaction, causing it to roll back.
So I'm left with one other option: push the requirement on the caller to cleanup their context before the call. This works:
Code:
@Component
public class CleanSlateContextHelper {
public static interface Delegate {
void doWork();
}
// sets up a new transactional context to absorb the caller's context, but not commit it.
@Transactional( propagation = Propagation.REQUIRES_NEW, readOnly = true )
public void doWork( Delegate delegate ) {
delegate.doWork();
}
}
... and the caller
Code:
@Resource
private SystemLogService systemLogService;
@Resource
private CleanSlateContextHelper cleanSlateContextHelper;
private void log( final Throwable throwable, final String errorId ) {
cleanSlateContextHelper.doWork( new CleanSlateContextHelper.WorkDelegate() {
@Override
public void doWork() {
// this is the write method from my first post, marked propagation=REQUIRES_NEW
systemLogService.write( throwable, errorId );
}
} );
}
So there's a read-only transaction setup to absorb the caller's context, which gets suspended when calling the desired method, finally setting up a clean context. This works but it's rather hacky, and imposes a constraint on the caller which I'd like to avoid. Do you know a better way?