2012-03-31 13 views
15

Necesito una forma de especificar dinámicamente la unidad de persistencia en un EJB.Nombre de la unidad de persistencia dinámica JPA

ejemplo simplificado:

Tengo una aplicación utilizando múltiples bases de datos como almacenes de datos. Cada uno de los almacenes de datos es estructuralmente el mismo. Según el cliente que se conecte a la aplicación, necesito acceder a los datos del un almacén de datos específico.

Por lo tanto, me gustaría utilizar el mismo EJB para que la lógica de negocios no esté duplicada, , pero solo seleccione la unidad de persistencia correcta en función del cliente.

Hasta ahora, solo he inyectado directamente el administrador de entidades con el nombre de unidad de persistencia codificado. ¿Hay alguna manera de inyectar dinámicamente el administrador de entidades con la unidad de persistencia requerida adjunta al EJB? Además, ¿las unidades de persistencia se pueden agregar dinámicamente durante el tiempo de ejecución? Actualmente, tengo que especificar la unidad de persistencia en el archivo persistence.xml. Idealmente, me gustaría crear pools en el servidor jdbc/db1, jdbc/db2, etc., según se requiera, mientras el sistema se está ejecutando. A continuación, solo agréguelos a la base de datos central del cliente y vincúlela a un cliente, de modo que cuando el cliente se conecte, verifique el nombre del grupo y lo use cuando llame al EJB para obtener la unidad de persistencia.

Todavía soy nuevo en el desarrollo de Java EE. Cualquier ayuda sería muy apreciada.

Respuesta

8

En la versión actual de JPA, desafortunadamente no es posible crear unidades de persistencia de forma dinámica. Si esta funcionalidad es importante para usted, usted podría considerar la creación de un tema JIRA para ello en el seguimiento de incidencias JPA: http://java.net/jira/browse/JPA_SPEC

Utilizando la anotación @PersistenceContext, tampoco es posible seleccionar dinámicamente una unidad de persistencia específico. Este es en realidad el dominio de la fragmentación, que Hibernate una vez trató de abordar, pero luego se suspendió repentinamente. Ver http://www.hibernate.org/subprojects/shards.html

Sin embargo, hay algunas cosas que podría hacer para obtener un efecto similar.

Un enfoque es crear un bean de fábrica EJB/CDI sin estado, que se inyecta con todos los administradores de entidad. El costo de esto es marginal, ya que esos granos se agruparán y los gerentes de entidades no son tan caros de crear en primer lugar.

Si también desea inyectarlos en función de alguna condición, entonces esta condición tendrá que estar disponible desde el contexto o debe especificarse en el punto de inyección (pero si lo hiciera, también podría inyectar el administrador de la entidad correcta directamente).

Un ejemplo patada de salida:

@Stateless 
@TransactionAttribute(SUPPORTS) 
public class ShardingEntityManagerFactory { 

    @Resource 
    private SessionContext sessionContext; 

    @PersistenceContext(unitName = "pu1") 
    private EntityManager entityManager1; 

    @PersistenceContext(unitName = "pu2") 
    private EntityManager entityManager2; 

    @Produces @TransactionScoped @ShardedPersistenceContext 
    public EntityManager getEntityManager() { 
     if (sessionContext.isCallerInRole("FOO")) { 
      return entityManager1; 
     } else { 
      return entityManager2; 
     } 
    } 
} 

Y luego, en sus granos:

@Stateless 
public class SomeBean { 

    @Inject @ShardedPersistenceContext 
    private EntityManager entityManager; 

    // ... 
} 

Tenga en cuenta que lo que se necesita Seam Persistencia aquí por la @TransactionScoped anotación. También podría ser más fácil, pero un poco más detallado, olvidarse de inyectar transparentemente el administrador de entidades e inyectar el ShardingEntityManagerFactory y obtener el correcto de él manualmente.

+0

Esto es casi lo que necesito, pero aún tengo que definir cada unidad de persistencia por adelantado en SharedEntityManagerFactory. Me hubiera gustado poder agregarlos dinámicamente para que no se requieran cambios de código y no se requiera una nueva implementación. Simplemente puedo guardar los detalles de la unidad de persistencia en la base de datos principal y vincularla con el cliente cuando sea necesario. Pero esto ya es mucho mejor que implementar cada almacén de datos como un servicio web independiente. Mucho menos sobrecarga. El servicio web tiene la ventaja adicional de poder almacenar la URL en db y usarla dinámicamente. Tendré que subir las opciones. – likenoother

3

Esto probablemente no es de ayuda para resolver el problema, pero es posible que le interese saber que este tipo de problemas está en discusión para la implementación de JPA 2.1

Esto suena como uno de esos casos de multitenancy:

Proposal for Multitenancy Support in JPA 2.1 JSR-338

+0

Creo que es técnicamente no tan lejano de multitenancy de hecho, pero mientras que hay una sola base de datos se divide en partes iguales y compartida entre varios inquilinos, aquí un arrendatario singe quiere múltiples DBs que aparecen como uno solo. –

+0

@ArjanTijms es correcto. Lo que estoy buscando es similar al multitenencia, pero en lugar de usar una base de datos, me gustaría usar más que en la base de datos. Quizás valga la pena separar cada base de datos en implementaciones EJB separadas y luego conectarse a través del servicio web. No me gusta la sobrecarga, pero al menos me da la libertad de apoyar bases de datos en diferentes sistemas si es necesario. Almacene clientes en diferentes máquinas. ¿No está seguro si se pueden usar interfaces remotas para esto? – likenoother

+0

@likenoother buen pensamiento! Sí, la única manera dinámica de agregar unidades de persistencia a un sistema en ejecución es desplegando en caliente los módulos EJB (ejb jarras) en un AS. Buscar beans de lo que técnicamente son "diferentes aplicaciones en el mismo AS" a través de una interfaz local no está especificado, pero en realidad funciona en la práctica. En lugar de inyectar esos beans directamente, puede usar búsquedas JNDI programáticas para obtener dinámicamente beans que encapsulan esas unidades persistentes añadidas dinámicamente. Sin embargo, la configuración es un poco heterodoxa, pero podría funcionar. –

1

Sólo una idea, no estoy seguro si va a ayudar: Usted puede abrir una flujoEntrada para leer el archivo persistence.xml y reemplazar estas líneas:

<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/agendasccv2?zeroDateTimeBehavior=convertToNull"/> 
<property name="javax.persistence.jdbc.password" value="btxbtxbtx"/> 
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> 
<property name="javax.persistence.jdbc.user" value="root"/> 

Luego salpique una pantalla de configuración de conexión en la que el usuario inicia una sesión, y establezca la conexión de acuerdo con los privilegios del usuario en ese archivo, a continuación, iniciar la aplicación principal

No estoy seguro de si esto ayuda, es sólo y la idea. Depende de su aplicación y lógica comercial.

2

Puede usar la misma unidad de persistencia para esto. Solo debe proporcionar un Mapa de propiedades cuando llame a createEntityManagerFactory() con el url/datasource que desea utilizar.

+0

Buena idea, pero eso no funciona en ¿Lo hace un entorno Java EE? Puede inyectar una fábrica de em, pero el método de creación solo es para entornos Java SE. –

Cuestiones relacionadas