How to execute JPA code out side spring transaction

Amit Patil :

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?

Andronicus :

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.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=307129&siteId=1