简体   繁体   English

具有多个持久性单元的Spring Data JPA CDI集成

[英]Spring Data JPA CDI integration with multiple persistence units

I am new to Spring and trying to integrate Spring Data, EclipseLink, and EJB on Weblogic 12c. 我是Spring的新手,正在尝试在Weblogic 12c上集成Spring Data,EclipseLink和EJB。

I want to use CDI to inject a Spring Data Repository into a stateless EJB so I followed the Spring Data CDI integration instruction and succeeded with single persistence unit. 我想使用CDI将Spring Data Repository注入到无状态EJB中,所以我遵循了Spring Data CDI集成指令并成功使用了单个持久性单元。

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

As the application requires two persistence units to connect two different databases, I configured two persistence units with a different name in persistence.xml. 由于该应用程序需要两个持久性单元来连接两个不同的数据库,因此我在persistence.xml中配置了两个具有不同名称的持久性单元。

Here comes the question: How can I create two Spring Data repository so that RepositoryA uses persistence Unit A and RepositoryB uses persistence Unit B? 问题来了:如何创建两个Spring Data存储库,以便RepositoryA使用持久性单元A和RepositoryB使用持久性单元B?

persistence.xml 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>

Primary CDI Producer: 主要的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();
    }
}

TL; TL; DR; DR;

Use qualifiers to declare which repository should use which EntityManager . 使用限定符声明哪个存储库应使用哪个EntityManager

Explanation 说明

Spring Data JPA repositories are implemented by default on a single EntityManager . Spring Data JPA存储库默认情况下在单个EntityManager The CDI extension propagates any qualifiers from the repository interface to its EntityManager selection. CDI扩展会将所有限定符从存储库接口传播到其EntityManager选择。 Because the qualifiers are effectively empty (not counting in @Default and @Any ), the extension uses the single EntityManager from your code above. 由于预选赛是有效的空(在不包括@Default@Any ),扩展使用单一EntityManager从上面的代码。

Creating and adding own qualifier annotations will do the job for you: 创建和添加自己的限定词注释将为您完成这项工作:

Qualifiers 预选赛

@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 {

}

Repository interfaces 仓库接口

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

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

Client-side usage interfaces 客户端使用界面

public class MyComponent {

    @Inject
    @MyFirstDatabase 
    SomeRepository someRepo;

    @Inject    
    @MySecondDatabase 
    SomeOtherRepository someOtherRepo;
}

Your EntityManagerFactoryProducer : 您的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();
    }
}

The code above assumes that you work with entity types that are not the same across your two data sources. 上面的代码假设您使用的实体类型在两个数据源中是不同的。 If you need to use the same entity type, then you would create a base repository interface, annotate it with @NoRepositoryBean and two derived interfaces, similar to the code above. 如果需要使用相同的实体类型,则可以创建一个基础存储库接口,并使用@NoRepositoryBean和两个派生接口对其进行注释,类似于上面的代码。

Based on mp911de's answer. 基于mp911de的答案。 The EntityManagerFactoryProducer requires two more close methods otherwise deployment fails on Weblogic. 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();
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM