tags:

views:

90

answers:

1

Using a ClassPathXmlApplicationContext object I want to get the same EntityManager that is being used by other parts of the app which get it injected via:

@PersistenceContext(unitName="accessControlDb") private EntityManager em;

Using ctx.getBean("access-emf") I can get the EntityManagerFactory which is defined in the applicationContext.xml. Using that I can create a new EntityManager, but I can't get the existing EntityManager used by the rest of the app.

I just can't figure out what code is executed to inject the value for the @PersistenceContext annotation.

<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>


<bean id="innerNgsdpDataSource" class="org.enhydra.jdbc.standard.StandardXADataSource">
    <property name="driverName" value="${ngsdp.jdbc.driver}"/>
    <property name="url" value="${ngsdp.jdbc.url}"/>
    <property name="user" value="${ngsdp.jdbc.username}"/>
    <property name="password" value="${ngsdp.jdbc.password}"/>
    <property name="transactionManager" ref="jotm"/>
</bean>

<bean id="ngsdpDataSource" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource">
    <property name="transactionManager" ref="jotm"/>
    <property name="dataSource" ref="innerNgsdpDataSource"/>
    <property name="user" value="${ngsdp.jdbc.username}"/>
    <property name="password" value="${ngsdp.jdbc.password}"/>
    <property name="maxSize" value="4"/>

    <property name="checkLevelObject" value="2"/>
    <property name="jdbcTestStmt" value="select 1 from dual"/>
</bean>

<bean id="myEmf" name="moservices" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="ngsdpDataSource"/>
    <property name="persistenceXmlLocation" value="WEB-INF/moservices-persistence.xml" />
    <property name="jpaVendorAdapter" ref="hibernate_jpa_vendor_adapter" />
    <property name="jpaPropertyMap" ref="jpa_property_map"/>
    <property name="jpaDialect" ref="hibernate_jpa_dialect"/>
</bean>
+1  A: 

If using spring-managed transactions, you can get the current EntityManager by calling

EntityManagerFactory emFactory = ctx.getBean("access-emf");
EntityManagerHolder emHolder = 
        (EntityManagerHolder) TransactionSynchronizationManager.getResource(emFactory);
EntityManager em = emHolder.getEntityManager();

This is most often the current EntityManager. But this is something which should be avoided (except possibly in unit-tests), as stated in the spring docs:

To be used by resource management code but not by typical application code

Another approach might be to intercept your service calls using Spring AOP, inject the @PersistenceContext in the advice, and set in in a ThreadLocal of yours. Later, you can get it from that ThreadLocal.

Bozho
This doesn't seem to work. It only returns null. In fact, TransactionSynchronizationManager.getResourceMap() returns an empty map. I marked the method as @Transactional. What else do I need to do to get it to work?
HappyEngineer
give more details about your transaction configuration. if getResourceMap returns empty map, this means you are not using spring-managed transactions.
Bozho
I'm using this: <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>and then I use it like this: <bean id="innerNgsdpDataSource" class="org.enhydra.jdbc.standard.StandardXADataSource"> <property name="driverName" value="${ngsdp.jdbc.driver}"/> <property name="url" value="${ngsdp.jdbc.url}"/> <property name="user" value="${ngsdp.jdbc.username}"/> <property name="password" value="${ngsdp.jdbc.password}"/> <property name="transactionManager" ref="jotm"/> </bean>
HappyEngineer
Oops. The code isn't formatted in comments, so I added the xml to the original question above.
HappyEngineer
yup, you are not using spring managed transactions. If everything else is working fine for you, better retain your configuration. Spring has JpaTransactionManager, which, if used, will have the EntityManager in the TransactionSynchronizationResource.
Bozho
I added another approach to my answer.
Bozho