2017-06-06 21 views
2

我有这样的要求,即每个客户端必须将其数据单独存储在单独的数据库中。在混合租户环境中生成EntityManager上下文

我想实现以下结构:

  1. 一个全球性的微服务处理身份验证,并提供了有关该客户端数据存储在数据库中的信息。
  2. 其他微服务在请求时会查询auth服务以了解客户端数据库信息,然后才会生成实体管理器。

我在努力正确管理EntityManagerFactory实例的状态。

我试图存储在WeakHashMap,但一些错误的事情开始发生。像一个简单的findById抛出异常。

我实际上在Payara服务器上使用运行DeltaSpike数据的JEE。

任何人都曾使用过类似的堆栈吗?

+0

一些代码可能有助于重新验证您的问题。 – FieryCat

+0

在部署时(甚至在开发时)固定和已知数据库集? –

+0

不,它的动态@NikosParaskevopoulos –

回答

0

如果您使用的是bean managed transaction,那么使用CDI来管理这种实体管理器工厂资源变得更加容易。

首先创建一个数据源上下文注释。

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

    /** 
    * This may be the database url or whatever. 
    */ 
    @Nonbinding 
    String value() default ""; 

} 

@SuppressWarnings("AnnotationAsSuperInterface") 
public class DatasourceLiteral extends AnnotationLiteral<Datasource> implements Datasource { 

    private static final long serialVersionUID = 7485753390480718735L; 

    private final String dbName; 

    public DatasourceLiteral(final String dbName) { 
     this.dbName = dbName; 
    } 

    @Override 
    public String value() { 
     return dbName; 
    } 

} 

@ApplicationScoped 
public class EntityManagerFactoryProvider { 

    @Produces 
    @Datasource 
    @ApplicationScoped 
    public EntityManagerFactory entityManagerFactory(final InjectionPoint ip) { 
     final Annotated annotated = ip.getAnnotated(); 
     final Datasource datasource = annotated.getAnnotation(Datasource.class); 

     /** 
     * Add relevant jpa properties 
     */ 
     final Map<String, String> jpaProperties = new HashMap<>(); 

     /** 
     * The main point is here. 
     */ 
     jpaProperties.put("javax.persistence.jdbc.url", datasource.value()); 

     return Persistence.createEntityManagerFactory("persistence-unit-jpa", jpaProperties); 
    } 

    public void dispose(@Disposes @Datasource final EntityManagerFactory emf) { 
     emf.close(); 
    } 

} 

@ApplicationScoped 
public class ExampleUserDatasource { 

    @Any 
    @Inject 
    private Instance<EntityManagerFactory> entityManagerFactories; 

    public void doSomething(final String user) { 
     final UserInfo userInfo = authenticationService.getUser(user); 
     final Datasource datasource = new DatasourceLiteral(userInfo.getDatasource()); 
     final EntityManagerFactory entityManagerFactory = entityManagerFactories.select(datasource).get(); 

     /** 
     * You could also actually inject this. 
     * Do whatever you want with it inside a transaction and close it too. 
     */ 
     final EntityManager entityManager = entityManagerFactory.createEntityManager(); 
    } 

} 
+0

提供的代码不起作用,'6:无法在非依赖范围的bean中注入注入点元数据:[BackedAnnotatedParameter] [BackedAnnotatedMethod] @Produces @Datasource @ApplicationScoped public parameter的参数1。 backend.comum.producers.EntityManagerFactoryProducer.entityManagerFactory(InjectionPoint)' –