spring LocalContainerEntityManagerFactoryBean does not work with persistentunitmanager - spring

I want to use LocalContainerEntityManagerFactoryBean with multiple persistence units.
applicationContext.xml:
<bean id="jpaEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="jpaPersistenceUnitManager"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="false"/>
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
</bean>
</property>
</bean>
<bean id="jpaPersistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="defaultPersistenceUnitName" value="pu-user”/>
<property name="persistenceXmlLocations">
<list>
<value>classpath*:META-INF/persistence-user.xml</value>
<value>classpath*:META-INF/persistence-customer.xml</value>
</list>
</property>
<property name="dataSources">
<map>
<entry key=“userDataSource" value-ref=“userDataSource"/>
<entry key="customerDataSource" value-ref=“customerDataSource"/>
</map>
</property>
<property name="defaultDataSource" ref=“userDataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" primary="true">
<property name="entityManagerFactory" ref="jpaEntityManagerFactory"/>
</bean>
<tx:annotation-driven proxy-target-class="true"/>
<context:component-scan base-package="simple.user.persistence"/>
<context:component-scan base-package="simple.customer.persistence"/>
persistence xmls are defined as follows:
<persistence-unit name="pu-user" transaction-type="RESOURCE_LOCAL">
<jta-data-source>userDataSource</jta-data-source>
<non-jta-data-source>userDataSource</non-jta-data-source>
</persistence-unit>
DataSources are defined as follows:
<bean id="userDataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/user"/>
<property name="username" value="user"/>
<property name="password" value="password"/>
<property name="maxTotal" value="32"/>
<property name="maxIdle" value="32"/>
<property name="validationQuery" value="select 1"/>
</bean>
UserRepository and CustomerRepository are defined as follows:
package simple.user.persistence;
#Repository
public class UserRepository {
#PersistenceContext(unitName="pu-user”)
EntityManager em;
#Transactional
User createUser(User user) {
em.persist(user);
}
}
When I run my unit test, I am getting the following exception.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'pu-customer' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:698)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1175)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.orm.jpa.EntityManagerFactoryUtils.findEntityManagerFactory(EntityManagerFactoryUtils.java:139)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findNamedEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:556)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:538)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:707)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:680)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:169)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:354)
... 60 more
Looked at the source code for EntityManagerFactoryUtils. The findEntityManagerFactory method at line 132 clearly compares only the defaultPersistentUnitName and ignores other persistent unit names defined in DeafultPersistentUnitManager. This looks to me like a bug. Please let me know what do you think.
https://github.com/spring-projects/spring-framework/blob/master/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java

When I've needed multiple persistence units I create multiple LocalContainerEntityManagerFactoryBean and then each LocalContainerEntityManagerFactoryBean would have a corresponding JpaTransactionManager.
The one ripple is that if you have multiple transaction managers you would need to name the transaction manager you want to use in the #Transactional annotation.
I suppose if you need to be accessing both persistence units within a single transaction you would need a JTA transaction manager to marry the 2 JPA transaction managers -- not sure what your requirements are for that though.

Related

Reg Spring Batch Transaction

My Requirement is I need to have two datasource connected to Spring Batch Application.
1) One for Spring Batch Jobs and Executions storing
2) One for Business Data Stroing, Processing and Retreiving.
I know that there are lot of solutions for achieving this. But I have achieved by setting the second datasource as primary. The problem is the second datasource is not coming under transaction scope instead it is committing for each sql statement executing expecially through jdbctemplate.
As I can't able to edit my question. I am writing another Post in detail
My Requirement is I need to have two datasource connected to Spring Batch Application.
1) One for Spring Batch Jobs and Executions storing
2) One for Business Data Stroing, Processing and Retreiving.
In env-context.xml I have following configuration
<!-- Enable annotations-->
<context:annotation-config/>
<bean primary="true" id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/DB2XADS"/>
</bean>
<!-- Creating TransactionManager Bean, since JDBC we are creating of type
DataSourceTransactionManager -->
<bean id="transactionManager" primary="true"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- jdbcTemplate uses dataSource -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="batchTransactionManager"
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
In override-context.xml I have the following code
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- jdbcTemplate uses dataSource -->
<bean id="batchDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/MySqlDS"/>
</bean>
<bean class="com.honda.pddabulk.utility.MyBatchConfigurer">
<property name="dataSource" ref="batchDataSource" />
</bean>
<!-- Use this to set additional properties on beans at run time -->
<bean id="placeholderProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/org/springframework/batch/admin/bootstrap/batch.properties
</value>
<value>classpath:/batch/batch-mysql.properties</value>
<value>classpath:log4j.properties</value>
</list>
</property>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="ignoreResourceNotFound" value="true"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="order" value="1"/>
</bean>
<!-- Overrider job repository -->
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="databaseType" value="mysql"/>
<property name="dataSource" ref="batchDataSource"/>
<property name="tablePrefix" value="${batch.table.prefix}"/>
<property name="maxVarCharLength" value="2000"/>
<property name="isolationLevelForCreate" value="ISOLATION_SERIALIZABLE"/>
<property name="transactionManager" ref="batchTransactionManager"/>
</bean>
<!-- Override job service -->
<bean id="jobService" class="org.springframework.batch.admin.service.SimpleJobServiceFactoryBean">
<property name="tablePrefix" value="${batch.table.prefix}"/>
<property name="jobRepository" ref="jobRepository"/>
<property name="jobLauncher" ref="jobLauncher"/>
<property name="jobLocator" ref="jobRegistry"/>
<property name="dataSource" ref="batchDataSource"/>
</bean>
<!-- Override job launcher -->
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
<property name="taskExecutor" ref="jobLauncherTaskExecutor" />
</bean>
<task:executor id="jobLauncherTaskExecutor" pool-size="21" rejection-policy="ABORT" />
<!-- Override job explorer -->
<bean id="jobExplorer"
class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
<property name="tablePrefix" value="${batch.table.prefix}"/>
<property name="dataSource" ref="batchDataSource"/>
</bean>
In job-config.xml I have the following code
<context:component-scan base-package="com.honda.*">
<context:exclude-filter type="regex"
expression="com.honda.pddabulk.utility.MyBatch*" />
</context:component-scan>
I have the custom Batch configurer set. Now the problem is when I try to execute queries with jdbctemplate for update and insert it is not under transaction which means #Transactional is not working.
Rather commit is happening for each method call. The example is
#Transactional
public void checkInsertion() throws Exception{
try{
jdbcTemplate.update("INSERT INTO TABLE_NAME(COLUMN1, COLUMN2) VALUES( 'A','AF' );
throw new PddaException("custom error");
}catch(Exception ex){
int count=jdbcTemplate.update("ROLLBACK");
log.info("DATA HAS BEEN ROLLBACKED SUCCESSFULLY... "+count);
throw ex;
}
}
In the above code I am trying to insert data and immediately I am also throwing a exception which means the insert should happen but commit will not. So we will not be able to see any data but unfortunately the commit is happening. Please some one help

EntityManager + #Transactional

#Service
#Repository
#Transactional
public class VideoService {
#PersistenceContext
EntityManager entityManager;
public void save(Video video) {
Video video1 = new Video();
entityManager.persist(video1);
}
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="video_pu" transaction-type="RESOURCE_LOCAL" >
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
</properties>
</persistence-unit>
</persistence>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/video" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="video_pu"/>
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- post-processors for all standard config annotations -->
<context:annotation-config/>
The transaction in service method save(Video video) is never started so also never commited. Where is the error? When I use EntityManagerFactory it works perfectly, but I don't want to explicitly begin and commit transaction. I want to use it with #Transactional annotation.
#beerbajay is correct, #Transactional will need a dynamic proxy to be created on your bean to apply the transactional logic, which can be created if your Service has an interface, since in your case it doesn't an alternate would be to instruct Spring to create class based proxy, the following way:
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class='true/>

multiple databases with Spring Data JPA

I'm trying to use Spring Data JPA with 2 databases in project. But an exception is triggered when I'm trying to run the application:
07:21:47.734 [main] ERROR o.s.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'deviceRepository': Injection of persistence dependencies failed; nested exception is 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.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:342) ~[spring-orm-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
...
Here is my applicationContext.xml
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource1">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url1}"/>
<property name="username" value="${database.username1}"/>
<property name="password" value="${database.password1}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager1">
<property name="entityManagerFactory" ref="entityManagerFactory1"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager1"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory1">
<property name="persistenceUnitName" value="persistenceUnit1"/>
<property name="dataSource" ref="dataSource1"/>
</bean>
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource2">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url2}"/>
<property name="username" value="${database.username2}"/>
<property name="password" value="${database.password2}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager2">
<property name="entityManagerFactory" ref="entityManagerFactory2"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager2"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory2">
<property name="persistenceUnitName" value="persistenceUnit2"/>
<property name="dataSource" ref="dataSource2"/>
</bean>
Here is my DAO interface:
#Repository
public interface DeviceRepository extends JpaRepository<Device, DevicePK>,
JpaSpecificationExecutor<Device> {
}
I've read a lot about #PersistenceContext but I never saw usages with JpaRepository.
Well you do have 2 entitymanagers.
I've never used JPARepository, but if it works close to its counter parts on spring-data for nosql, Spring will enhance the class, and probably inject the EM on it. Your problem is that you have 2 EM declared.
Have a look at the spring-jpa docs, they'll show you how to configure the repository for how you can add specific EMF to your repos
Long story short:
You have to create custom implementation of that interface and that implementation has to contain entity manager declared as:
#PersistenceContext(unitName = "persistenceUnit1")
private EntityManager entityManager;
if you want to use persistence unit 1.
Check this out: http://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/repositories.html#repositories.custom-implementations, it also has examples and example 1.17 (little bit down the page) implements interface and has entity manager in it and that entity manager is passed on to super constructor.
You may also take a look at Spring Data - JPA, customizing Repository not working, it has implementation of interface that extends JpaRepository and it also has entity manager declared in implementation. Just add unitName to #PersistenceContext annotation and try it that way.
You may not need any custom methods (so your interface can be empty) but you do need constructor that passes on entity manager and all that tinkering with extending your own interface to bypass default automatic wiring behaviour.
One of the two datasource must be defined as primary.
<bean> has a primary attribute that can be set to true or false:
<bean primary="true|false"/>
Usually in #Configuration the #Primary annotation is placed to:
EntityManager
DataSource
TransactionManager
So you can try to add primary="true"
to the following beans:
dataSource1
transactionManager1
entityManagerFactory1

Spring JPA provider produces wring exception on optimistic lock failure

In case there is failure in optimistic locking I expect JPA entity manager to throw javax.persistence.OptimisticLockingException
Yet when I use spring orm jpa it provides ObjectOptimisticLockingException which is not related with expected one - so the question is, WTF? Do I misunderstand JPA documentation, or did the spring guys ignored standarts?
Most funny thing is that in JUnit test case proper exception is thrown ( Wrapping StaleObjectException ),
while in web app it is FUBAR. Spring configuration is reused for unit test.
Here is some code for clarity :
<!-- JPA entity manager configuration -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${database.driver}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="testOnBorrow" value="${database.testonborrow}"/>
<property name="validationQuery" value="${database.validationquery}"/>
</bean>
<bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="defaultDataSource" ref="dataSource"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager"/>
<property name="persistenceUnitName" value="provisioning"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true"/>
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.dialect" value="${hibernate.dialect}"/>
<entry key="hibernate.hbm2ddl.auto" value="${hibernate.hbm2ddl.auto}" />
<entry key="hibernate.hbm2ddl.delimiter.type" value="InnoDB" />
<entry key="hibernate.show_sql" value="${hibernate.show_sql}" />
</map>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<context:annotation-config/>
<tx:annotation-driven/>
It's not a bug, it's a feature. Spring's HibernateTemplate and its interceptors around repositories translate exceptions into Spring exceptions. The idea is that if you have a Hibernate-based DAO, an iBatis-based DAO or a JDBC-based DAO, they all throw the same types of exceptions, so that the client code doesn't have to care.
See http://static.springsource.org/spring/docs/3.1.0.M2/spring-framework-reference/html/dao.html#dao-exceptions

In spring, what code is used to inject the value for the #PersistenceContext annotated variables?

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>
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.

Resources