首页 > 解决方案 > 如何在 Spring 事务之外执行 JPA 代码

问题描述

我想优化只读查询,所以我想在事务之外执行 JPQL 查询,这样从 JPQL 返回的实体将不会在当前持久性上下文中进行管理(为了节省脏检查的成本和不必要的管理这些实体以节省 2X 大小在持久性上下文中)。

我在下面尝试过,

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

呼叫者,

@Test
public void jpqlTest() {
    customPostRepository.foo();
}

我想EmployeeRepository#bar在事务之外执行(由 C 创建ustomPostRepository#bar),但Propagation.NOT_SUPPORTED不工作,所有从 JPQL 中选择的实体都在当前持久性上下文中进行管理。

那么,有什么办法可以避免管理这些实体或在事务之外执行代码呢?或者这里缺少什么?

标签: javaspringjpaspring-data-jpaspring-data

解决方案


您应该删除@Transactional注释。在这种情况下,除非方法本身不 throw ,否则它不会产生影响LazyInitializationException。如果存在需要事务的情况,则必须为它创建一个单独的方法/从同一个 bean 调用它,这样就不会创建代理。

EntityManager#contains也不检查进程是否在事务中运行或实体被脏检查。

如果您不想/不能更改这些方法,请使用EntityManager#detach.


推荐阅读