【问题标题】:Spring Data JPA CDI integration with multiple persistence unitsSpring Data JPA CDI 与多个持久性单元的集成
【发布时间】:2018-05-11 15:28:56
【问题描述】:

我是 Spring 新手,正在尝试在 Weblogic 12c 上集成 Spring Data、EclipseLink 和 EJB。

我想使用 CDI 将 Spring Data Repository 注入到无状态 EJB 中,因此我遵循 Spring Data CDI 集成说明并成功使用了单个持久性单元。

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpd.misc.cdi-integration

由于应用需要两个持久化单元来连接两个不同的数据库,所以我在persistence.xml中配置了两个不同名字的持久化单元。

问题来了:如何创建两个 Spring Data 存储库,以便 RepositoryA 使用持久性单元 A 和 RepositoryB 使用持久性单元 B?

persistence.xml

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
    <persistence-unit name="PRIMARY_PU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/EMP_DS</jta-data-source>
        <class>com.smec.eis.example.springbooteval.model.Employee</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
    </persistence-unit>
    <persistence-unit name="SECONDARY_PU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/HR_DS</jta-data-source>
        <class>com.smec.eis.example.springbooteval.model.Job</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
    </persistence-unit>
</persistence>

主要 CDI 生产者:

public class EntityManagerFactoryProducer {

    @Produces
    @ApplicationScoped
    public EntityManagerFactory createEntityManagerFactory() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PRIMARY_PU");
        return emf;
    }

    public void close(@Disposes EntityManagerFactory entityManagerFactory) {
        entityManagerFactory.close();
    }

    @Produces
    @Dependent
    public EntityManager createEntityManager(EntityManagerFactory entityManagerFactory) {
        return entityManagerFactory.createEntityManager();
    }

    public void close(@Disposes EntityManager entityManager) {
        entityManager.close();
    }
}

【问题讨论】:

  • 为什么要在 Java EE 容器中使用 Spring Data?看看 DeltaSpike:deltaspike.apache.org/documentation/data.html DeltaSpike 是完全适合 Java EE 的 CDI 扩展
  • 我会看看 DeltaSpike。但是,如果我希望它在 JEE 容器和 Spring 容器中都可以工作,那么使用 Spring Data 作为数据访问层是否有正当理由?
  • 当然!但我的意见是使用 Spring 或 Java EE。使用 Spring,您可以使用任何 servlet 容器,例如 Tomcat 或 Spring。此外,Spring 提供了比普通 Java EE 更方便的功能
  • 我试过 DeltaSpike,我很喜欢。看起来 DeltaSpike 使 JEE 容器中的事情变得更容易,更好地支持容器管理的事务。由于我们使用的是 EJB 和 CMT,也许 DeltaSpike 会是更好的选择。
  • 当然。 DeltaSpike 是 CDI 扩展,而 Spring 是与 EJB 和 CDI 竞争的依赖注入容器。我永远不会把这两者混在一起。

标签: java spring-data spring-data-jpa eclipselink cdi


【解决方案1】:

TL;博士;

使用限定符来声明哪个存储库应该使用哪个EntityManager

说明

Spring Data JPA 存储库默认在单个 EntityManager 上实现。 CDI 扩展将任何限定符从存储库接口传播到其EntityManager 选择。因为限定符实际上是空的(不包括在 @Default@Any 中),所以扩展使用上面代码中的单个 EntityManager

创建和添加自己的限定符注释将为您完成这项工作:

预选赛

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@interface MyFirstDatabase {

}

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@interface MySecondDatabase {

}

存储库接口

@MyFirstDatabase
public interface SomeRepository extends CrudRepository<MyEntity, Long> { … }

@MySecondDatabase
public interface SomeOtherRepository extends CrudRepository<OtherEntity, Long> { … }

客户端使用接口

public class MyComponent {

    @Inject
    @MyFirstDatabase 
    SomeRepository someRepo;

    @Inject    
    @MySecondDatabase 
    SomeOtherRepository someOtherRepo;
}

你的EntityManagerFactoryProducer

public class EntityManagerFactoryProducer {

    @Produces
    @ApplicationScoped
    @MyFirstDatabase
    public EntityManagerFactory createEntityManagerFactory() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PRIMARY_PU");
        return emf;
    }

    @Produces
    @ApplicationScoped
    @MySecondDatabase
    public EntityManagerFactory createEntityManagerFactory() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("SECONDARY_PU");
        return emf;
    }

    public void close(@Disposes EntityManagerFactory entityManagerFactory) {
        entityManagerFactory.close();
    }

    @Produces
    @Dependent
    @MyFirstDatabase
    public EntityManager createEntityManager(@MyFirstDatabase EntityManagerFactory entityManagerFactory) {
        return entityManagerFactory.createEntityManager();
    }

    @Produces
    @Dependent
    @MySecondDatabase
    public EntityManager createEntityManager(@MySecondDatabase EntityManagerFactory entityManagerFactory) {
        return entityManagerFactory.createEntityManager();
    }

    public void close(@Disposes EntityManager entityManager) {
        entityManager.close();
    }
}

上面的代码假定您使用的实体类型在两个数据源中并不相同。如果您需要使用相同的实体类型,那么您将创建一个基本存储库接口,使用@NoRepositoryBean 和两个派生接口对其进行注释,类似于上面的代码。

【讨论】:

  • 非常感谢您的解释!我明天会尝试解决方案。
【解决方案2】:

基于 mp911de 的回答。 EntityManagerFactoryProducer 需要另外两个关闭方法,否则在 Weblogic 上部署会失败。

public class EntityManagerFactoryProducer {

    @Produces
    @ApplicationScoped
    @PrimaryEM
    public EntityManagerFactory createEntityManagerFactory() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PRIMARY_PU");
        return emf;
    }

    @Produces
    @Dependent
    @PrimaryEM
    public EntityManager createEntityManager(@PrimaryEM EntityManagerFactory entityManagerFactory) {
        EntityManager em = entityManagerFactory.createEntityManager();
        return em;
    }

    @Produces
    @ApplicationScoped
    @SecondaryEM
    public EntityManagerFactory createSecondaryEntityManagerFactory() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("SECONDARY_PU");
        return emf;
    }

    @Produces
    @Dependent
    @SecondaryEM
    public EntityManager createSecondaryEntityManager(@SecondaryEM EntityManagerFactory entityManagerFactory) {
        EntityManager em = entityManagerFactory.createEntityManager();
        return em;
    }

    public void close(@Disposes @PrimaryEM EntityManager entityManager) {
        entityManager.close();
    }


    public void close(@Disposes @PrimaryEM EntityManagerFactory entityManagerFactory) {
        entityManagerFactory.close();
    }

    public void closeSecondary(@Disposes @SecondaryEM EntityManager entityManager) {
        entityManager.close();
    }

    public void closeSecondary(@Disposes @SecondaryEM EntityManagerFactory entityManagerFactory) {
        entityManagerFactory.close();
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    • 2018-04-27
    • 1970-01-01
    • 2013-02-15
    • 2017-09-22
    • 1970-01-01
    相关资源
    最近更新 更多