2017-06-06 40 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)' –