I want to optimize read-only queries, So I want to execute JPQL query outside of transaction so that entities returned from JPQL will not be managed in current persistence context (To save the cost of dirty checking and unnecessary managing those entities to save 2X size in persistence context).
I tried below,
@Repository
public class CustomPostRepository {
@Autowired
private EmployeeRepository employeeRepository;
@Transactional
public void foo() {
// Some other transactional code (read-write) here ...
final TransactionStatus transactionStatus = TransactionAspectSupport.currentTransactionStatus(); // returns current active transaction
System.out.println("transactionStatus.isNewTransaction() = " + transactionStatus.isNewTransaction()); // returns TRUE
List<Post> posts = employeeRepository.bar();
// Some other code here...
}
}
@Repository
public class CustomJpaEmployeeDao implements EmployeeRepository {
@PersistenceContext
private EntityManager em;
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public List<Post> bar() {
// Ideally this method should throw Exception, as transaction is expected to be suspended (not exists here)
final TransactionStatus transactionStatus = TransactionAspectSupport.currentTransactionStatus();
final List<Post> post = em.createNamedQuery("Post.findAllForReporing", Post.class).getResultList();
System.out.println("entityManager.contains(post) = " + em.contains(post.get(0))); // returns true, which should be false
return post;
}
}
Caller,
@Test
public void jpqlTest() {
customPostRepository.foo();
}
I want to execute EmployeeRepository#bar
outside of transaction (created by CustomPostRepository#bar
), but Propagation.NOT_SUPPORTED
is not working and all selected entities from JPQL are managed in the current persistence context.
So, is there any way to avoid managing those entities or executing code outside of the transaction? or is something missing here?
You should remove @Transactional
annotation. In this case it won't make a difference unless the method itself doesn't throw LazyInitializationException
. If there was a case where transaction was needed, you would have to create a separate method for it / call it from the same bean, so that no proxy is created.
Also EntityManager#contains
does not check, if the process runs within transaction or entities are dirty-checked.
If you don't want to / can't change those methods, use EntityManager#detach
.