Reputation: 12416
Consider having two entity manager factories:
<bean id="writeEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">...</bean>
<bean id="readOnlyEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">...</bean>
Then I want to have two Beans to which I would inject the correct persistence context:
<bean id="readOnlyManager" class="..MyDatabaseManager">
<bean id="writeManager" class="..MyDatabaseManager">
The bean would look something like:
public class MyDatabaseManager {
private javax.persistence.EntityManager em;
public EntityManager(javax.persistence.EntityManager em) {
this.em = em;
}
...
}
This obviously doesn't work, because EntityManager is not a bean and cannot be injected in this way:
No qualifying bean of type 'javax.persistence.EntityManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
How can I qualify correct EntityManager in the bean? I used to use @PersistenceContext
annotation, but this is not usable as I need to inject it.
How can I specify the PersistenceContext for such Bean?
UPDATE: My question is how to inject PersistenceContext with qualifier via XML, not via annotation.
Upvotes: 10
Views: 3766
Reputation: 419
I suppose you are trying to inject an entityManager into your manager class
public class MyDatabaseManager {
// where you need to qualify your injection
private javax.persistence.EntityManager em;
public EntityManager(javax.persistence.EntityManager em) {
this.em = em;
}
...
}
here are the working codes for my project
Persistence.xml in META-INF folder
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="PERSISTENCE_UNIT_T" transaction-type="JTA">
<provider>foo.bar.PersistenceProvider</provider>
<jta-data-source>jdbc/DB2</jta-data-source>
</persistence-unit>
<persistence-unit name="PERSISTENCE_UNIT_P" transaction-type="JTA">
<provider>foo.bar.PersistenceProvider</provider>
<jta-data-source>jdbc/DB2</jta-data-source>
</persistence-unit>
</persistence>
Qualifier interface class SelectDataSource
@Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD }) public @interface SelectDataSource{}
EntityManager class
public class EntityManager {
public EntityManager() {
}
@Inject
@SelectDataSource
private EntityManager entityManager;
// other entity manager methods
}
Entity Manager Provider class to provide persistence unit based on context
public class EntityManagerProvider {
@PersistenceContext(unitName = "PERSISTENCE_UNIT_T")
private EntityManager entityManagerT;
@PersistenceContext(unitName = "PERSISTENCE_UNIT_P")
private EntityManager entityManagerP;
@Produces
@SelectDataSource
EntityManager createEntityManager(InjectionPoint injectionPoint) {
if (System.ENV.equalsIgnoreCase("p")) {
if (entityManagerP != null) {
return entityManagerP;
}
}
return entityManagerT;
}
}
then the EntityManager class can be injected to wherever you like with @Inject
Below is a nice post on how to use Context Dependency Injection to create managed entity manager https://www.sitepoint.com/cdi-weld-inject-jpa-hibernate-entity-managers/#usingaproducermethod
Upvotes: 0
Reputation: 5703
persistence.xml (2 persistence unit for 2 different entitymanager, based on your persistence provider here i ma using HibernatePersistence)
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="pu1">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
</persistence-unit>
<persistence-unit name="pu2">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
</persistence-unit>
</persistence>
Make sure you are assigning the persistence-unit to entity manager using property persistenceUnitName
<bean id="writeEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath: of yout persistence xml" />
<property name="persistenceUnitName" value="pu1" />
.....other configuration of em..
</bean>
same for other em.
Now, use constructor injection for MyDatabaseManager to inject EntityManager (using qualifier name ex. writeEntityManagerFactory )
<bean id="mdm" class="MyDatabaseManager">
<constructor-arg ref = "writeEntityManagerFactory"/>
</bean>
Upvotes: 1
Reputation: 6944
Assuming that you are using spring in order to manage transactions what I would do is 2 different transaction managers and then in my services i would use the most appropriate transaction manager like this:
Configuration section
@Bean
public LocalContainerEntityManagerFactoryBean writeEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
//Your configuration here
return factory;
}
@Bean(name={"writeTx"})
public PlatformTransactionManager writeTransactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(writeEntityManagerFactory().getObject());
return txManager;
}
@Bean
public LocalContainerEntityManagerFactoryBean readEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
//Your configuration here
return factory;
}
@Bean(name={"readTx"})
public PlatformTransactionManager readTransactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(readEntityManagerFactory().getObject());
return txManager;
}
Service layer
@Transactional(value="readTx")
public List<Object> read(){
//Your read code here
}
@Transactional(value="writeTx")
public void write(){
//Your write code here
}
UPDATED ANSWER I misunderstood the question.
In your configuration class you can define:
@Bean
public LocalContainerEntityManagerFactoryBean writeEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "models" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(hibProps());
em.setPersistenceUnitName("writer");
return em;
}
@Bean
public LocalContainerEntityManagerFactoryBean readEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "models" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(hibProps());
em.setPersistenceUnitName("reader");
return em;
}
Please see the PersistenceUnitName
values
Then you can injecting them by doing:
@PersistenceContext(unitName="writer")
private EntityManager emWriter;
@PersistenceContext(unitName="reader")
private EntityManager emReader;
I just tested it and all worked pretty good
Angelo
Upvotes: 2