首页 文章

如何在Spring容器之外使用Spring Data JPA?

提问于
浏览
43

我正在尝试手动连接Spring Data JPA对象,以便我可以生成DAO代理(也称为存储库) - 而无需使用Spring bean容器 .

不可避免地,我会被问到为什么要这样做:这是因为我们的项目已经在使用Google Guice(并且在使用Gin和GWT的UI上),我们不会't want to maintain another IoC container configuration, or pull in all the resulting dependencies. I know we might be able to use Guice' s SpringIntegration ,但这将是最后的选择 .

似乎所有东西都可用于手动连接对象,但由于它没有很好地记录,我现在遇到了困难 .

根据Spring Data用户指南,可以使用repository factories standalone . 不幸的是,该示例显示 RepositoryFactorySupport 这是一个抽象类 . 经过一番搜索,我找到了JpaRepositoryFactory

JpaRepositoryFactory 实际上工作得很好,除了它不会自动创建交易 . 必须手动管理事务,否则任何内容都不会持久保存到数据库:

entityManager.getTransaction().begin();
repositoryInstance.save(someJpaObject);
entityManager.getTransaction().commit();

问题原来是 @Transactional 注释没有自动使用,需要 TransactionInterceptor 的帮助

值得庆幸的是, JpaRepositoryFactory 可以在返回之前接受回调以向生成的Repository代理添加更多AOP建议:

final JpaTransactionManager xactManager = new JpaTransactionManager(emf);
final JpaRepositoryFactory factory = new JpaRepositoryFactory(emf.createEntityManager());

factory.addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() {
    @Override
    public void postProcess(ProxyFactory factory) {
        factory.addAdvice(new TransactionInterceptor(xactManager, new AnnotationTransactionAttributeSource()));
    }
});

这是事情进展不顺利的地方 . 单步执行代码中的调试器, TransactionInterceptor 确实正在创建一个事务 - 但错误的 EntityManager . Spring通过查看当前正在执行的线程来管理活动 EntityManager . TransactionInterceptor 执行此操作并看到没有活动的 EntityManager 绑定到该线程,并决定创建一个新的 .

但是,这个新的 EntityManager 与创建并传递到 JpaRepositoryFactory 构造函数的实例不同,后者需要 EntityManager . 问题是,如何使 TransactionInterceptorJpaRepositoryFactory 使用相同的 EntityManager

更新:

在写这篇文章时,我发现了如何解决问题,但它仍然可能不是理想的解决方案 . 我将此解决方案作为单独的答案发布 . 我很高兴听到有关使用Spring Data JPA独立的更好方法的建议,而不是我如何解决它 .

2 回答

  • 12

    设计 JpaRepositoryFactory 和相应的Spring集成 JpaRepositoryFactory bean背后的一般原则如下:

    我们假设您在托管JPA运行时环境中运行应用程序,而不是关心哪一个 .

    这就是我们依赖注入 EntityManager 而不是 EntityManagerFactory 的原因 . 根据定义, EntityManager 不是线程安全的 . 因此,如果直接处理 EntityManagerFactory ,我们将不得不重写所有资源管理代码,托管运行时环境(就像Spring或EJB)将为您提供 .

    为了与Spring事务管理集成,我们使用Spring的 SharedEntityManagerCreator ,它实际上是你手动实现的事务资源绑定魔法 . 所以你可能想用那个从你的 EntityManagerFactory 创建 EntityManager 实例 . 如果要直接激活存储库bean中的事务性(以便调用例如 repo.save(…) ,如果没有活动则创建事务),请查看Spring Data Commons中的 TransactionalRepositoryProxyPostProcessor 实现 . 它实际上在直接使用Spring Data存储库时激活事务(例如 repo.save(…) ),并稍微自定义事务配置查找以优先于实现类的接口,以允许存储库接口覆盖 SimpleJpaRepository 中定义的事务配置 .

  • 24

    我在使用 JpaRepositoryFactory 创建存储库之前,通过手动将 EntityManagerEntityManagerFactory 绑定到正在执行的线程来解决这个问题 . 这是使用 TransactionSynchronizationManager.bindResource 方法完成的:

    emf = Persistence.createEntityManagerFactory("com.foo.model", properties);
    em = emf.createEntityManager();
    
    // Create your transaction manager and RespositoryFactory
    final JpaTransactionManager xactManager = new JpaTransactionManager(emf);
    final JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
    
    // Make sure calls to the repository instance are intercepted for annotated transactions
    factory.addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() {
        @Override
        public void postProcess(ProxyFactory factory) {
            factory.addAdvice(new TransactionInterceptor(xactManager, new MatchAlwaysTransactionAttributeSource()));
        }
    });
    
    // Create your repository proxy instance
    FooRepository repository = factory.getRepository(FooRepository.class);
    
    // Bind the same EntityManger used to create the Repository to the thread
    TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em));
    
    try{
        repository.save(someInstance); // Done in a transaction using 1 EntityManger
    } finally {
        // Make sure to unbind when done with the repository instance
        TransactionSynchronizationManager.unbindResource(getEntityManagerFactory());
    }
    

    必须有更好的方法 . 看起来奇怪的是RepositoryFactory被设计为使用 EnitiyManager 而不是 EntityManagerFactory . 我希望,它首先会查看 EntityManger 是否绑定到该线程,然后创建一个新的并绑定它,或使用现有的 .

    基本上,我想注入存储库代理,并期望在每次调用时它们在内部创建一个新的 EntityManager ,以便调用是线程安全的 .

相关问题