Después en la aplicación, suponiendo que inyectamos el EntityManager a nuestros DAOs mediante la anotación @PersistenceContext, a cada uno de ellos habría que incluirle el atributo unitName especificado en el persistence.xml:
@PersistenceContext(unitName="defaultDB")
En mi caso esto no me ha valido porque en el momento de tener que conectar otra base de datos a mi aplicación, ésta importaba una serie de librerías comunes que utilizamos para más proyectos en los que había objetos DAO con un @PersistenceContext sin especificar ningún unitName. Cambiar la librería común para que especifira el unitName es inviable ya que en cada aplicación en la que se utiliza su valor es diferente.
Al arrancar la aplicación sin hacer nada la excepción que aparece es:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [javax.persistence.EntityManagerFactory] is defined: expected single bean but found 2
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:536)
Esta claro. El DAO que tiene el @PersistenceContext no sabe qué entityManager tiene que recibir y no podemos modificarlo para especificárselo.
En la excepción se puede ver que el error ocurre en el método findDefaultEntityManagerFactory de la clase PersistenceAnnotationBeanPostProcessor de Spring. Es el encargado de inyectar el entityManager a los @PersistenceContext.
Me he creado una clase que hereda de PersistenceAnnotationBeanPostProcessor y sobreescribe el método findDefaultEntityManagerFactory de tal manera que voy a devolver el entityManagerFactory que yo quiera. La clase en cuestión quedaría así:
public class PersistenceAnnotationBeanPostProcessor extends org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor{
private EntityManagerFactory defaultEntityManagerFactory;
protected EntityManagerFactory findDefaultEntityManagerFactory(String requestingBeanName)
throws NoSuchBeanDefinitionException{
if (defaultEntityManagerFactory!=null){
return defaultEntityManagerFactory;
}
return super.findDefaultEntityManagerFactory(requestingBeanName);
}
public void setDefaultEntityManagerFactory(
EntityManagerFactory defaultEntityManagerFactory) {
this.defaultEntityManagerFactory = defaultEntityManagerFactory;
}
}
Lo único que tendríamos hacer a continuación es definir un bean en la configuración de Spring con esta clase en vez de la que utiliza Spring por defecto:
Eso sí, tenemos que especificar en el atributo "defaultEntityManagerFactory" qué entityManager queremos que se inyecte cuando nos encontramos con un @PersistenceContext sin especificar un unitName.
La conexión a la segunda base de datos yo sólo la he utilizado para realizar consultas sobre ella, nunca para realizar modificaciones. No sé si habría algún fallo en las transacciones, ya que el JpaTransactionManager está ligado únicamente a un EntityManagerFactory.
hola marcos tengo una duda, ¿donde defines el bean? ¿en la configuracion de spring?
ResponderEliminarSi, en la configuración de Spring.
ResponderEliminarEn las aplicaciones normales se define un bean con la clase org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
En este caso en vez de usar la clase que nos proporciona Spring, utilizamos la nuestra com.mlopez.utils.spring.PersistenceAnnotationBeanPostProcessor indicando el defaultEntityManagerFactory.
hola marcos te cuento mi caso:
ResponderEliminarTengo dos aplicaciones (personal y productividad).
En el fichero config-datasource.xml tengo definidos los datasource y los entityManagerFactory.
He definido la clase especificada y el bean en el arhivo anterioremente citado pero me da error en uno de los dao's que tengo establecidos "expected single bean but found 2"
¿Puedes orientarme un poco porque es la primera vez que trabajo con jpa?
Por otro lado tambien me he creado dos unidades de persistencia en el persistence.xml
Y tambien tengo dos archivos orm donde tengo definidos los esquemas propietarios de las bbdd
La aplicaciones funcionan pero no insertan datos ni tampoco hacen actualizaciones si le pongo a pelo la clausula @PersistenceContext (unitname="")
en los Dao genericos de donde tiran los demas
gracias
Hola David.
ResponderEliminarMe da la sensación de que tienes la opción de utilizar la anotación @PersistenceContext especificando un unitName. Si ese es el caso, no te hace falta que hagas todo lo que he puesto en esta entrada.
En cada Dao que tengas pon un @PersistenceContext(unitName="personal") o (unitName="productividad"), si es así como los has llamado en sus persistence.xml.
Con eso, entiendo que debería funcionar sin necesidad de hacer nada más.
Un saludo
Poniendo el @PersistenceContext en cada dao funciona correctamente pero no inserta ni actualizar en las bbdd establecidas
ResponderEliminaralguna idea?
gracias
Pon la traza a ver si se me ocurre algo...
ResponderEliminarte pongo el config-datasource
ResponderEliminary te pongo el servicio que estoy intentando ejecutar:
no puedo mandartelo por tamaño
ResponderEliminarmi correo es marcos PUNTO lopez PUNTO miguel EN gmail PUNTO com
ResponderEliminarBuenas,
ResponderEliminartengo problemas igualmente para conectarme a dos BDD, por JPA bajo Hibernate usando Spring.
La cuestión que me da el mismo error que a ti cuando defino dos EntityManagerFactory pero con la solución que has puesto, los dos EntityManagerFacotry seguirán definidos y por lo tanto dará la misma excepción, no?
No tienes el código fuente completo?
Gracias