Friday, October 5, 2018

Injecting one of the two @PersistenceContext

Leave a Comment

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.

2 Answers

Answers 1

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

Answers 2

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> 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment