Spring 数据 JPA CDI 与多个持久化单元的集成
Spring Data JPA CDI integration with multiple persistence units
我是 Spring 的新手,正在尝试在 Weblogic 12c 上集成 Spring 数据、EclipseLink 和 EJB。
我想使用 CDI 将 Spring 数据存储库注入到无状态 EJB 中,所以我遵循 Spring 数据 CDI 集成说明并成功使用了单个持久性单元。
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpd.misc.cdi-integration
由于应用程序需要两个持久化单元来连接两个不同的数据库,所以我在persistence.xml中配置了两个不同名称的持久化单元。
问题来了:如何创建两个 Spring 数据存储库,以便 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();
}
}
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
和两个派生接口对其进行注释,类似于上面的代码。
基于 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();
}
我是 Spring 的新手,正在尝试在 Weblogic 12c 上集成 Spring 数据、EclipseLink 和 EJB。
我想使用 CDI 将 Spring 数据存储库注入到无状态 EJB 中,所以我遵循 Spring 数据 CDI 集成说明并成功使用了单个持久性单元。
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpd.misc.cdi-integration
由于应用程序需要两个持久化单元来连接两个不同的数据库,所以我在persistence.xml中配置了两个不同名称的持久化单元。
问题来了:如何创建两个 Spring 数据存储库,以便 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();
}
}
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
和两个派生接口对其进行注释,类似于上面的代码。
基于 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();
}