Issue while setting up spring annotation based transactions - java

I have an application which used mix of JPA and JDBC. I have successfully done setup for JPA transaction using #Transactional annotation, but I am not able to make it work for JDBC.
My configuration looks like:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<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"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
My code is :
#Test
#Transactional
public void testUpdateSQLwithParam() {
Object[] params = { "John","", "trol", "test", "M", "Place", "123456789",
"tom#domain.com" };
customQueryDao.insert("PERSON_INSERT_QUERY", params);
String sqlConstant = "PERSON_MASTER_UPADTE_QUERY";
params = new Object[]{ "Test", 8 };
customQueryDao.updateSQLwithParam(sqlConstant, params);
}
My JDBC code uses jdbcTemplate to execute queries. Please let me know how I can have JDBC transactions using #Transactional annotation. using jpatransactionmgr

You have 2 beans defined with the same id (transactionManager). Try it with a different ID, maybe like:
<bean id="jPATransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="dataSourceTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
This should work, you can also enable debugging on log4j to see transactions in your log files, here's what I have in my log4j.xml:
<!-- 3rdparty Loggers -->
<logger name="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<level value="debug" />
</logger>

I can see from you edit that you tried to fix the problem of multiple transaction manager. But I think you did not remove the good one ... From javadoc of JpaTransactionManager : This transaction manager also supports direct DataSource access within a transaction (i.e. plain JDBC code working with the same DataSource).
IMHO you should instead keep the JpaTransactionManager, and remove the DataSourceTransactionManager. (I have some code using plain JDBC mixed with Hibernate access with a single HibernateTransactionManager and transaction are correctly managed ...)

Related

Inject multiple datasources to single EntityManagerFactory?

I am trying to fetch data from two different tables of two different schemas (logical db) in same database server using innerjoin query +JPA nativesql. How can I inject multiple datasources to same entity manager?
my config file looks like this
<bean id="userDataSource" class="org.jdbcdslog.DataSourceProxy">
<description>Data source for User database</description>
<property name="targetDSDirect">
<bean class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/cUser" />
<property name="resourceRef" value="true" />
</bean>
</property>
</bean>
<bean id="masterDataSource" class="org.jdbcdslog.DataSourceProxy">
<description>Data source for User database</description>
<property name="targetDSDirect">
<bean class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/Master" />
<property name="resourceRef" value="true" />
</bean>
</property>
</bean>
<bean id="entitymanager" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation"
value="classpath:com/jpa_persistence.xml" />
<property name= "persistenceUnitName" value= "CP"/>
<property name="dataSource" ref="userDataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaPropertyMap">
<map>
<entry key="eclipselink.weaving" value="false"/>
</map>
</property>
</bean>
Most of the database engines i know do not required these kind of evil double datasource tricks, you can just grant read (or write) access to both schema on the same user.
This way the user will have access to both of those schemas and be able to cross query.
Finally use the Entity anotation to define which schema to use
#Entity
#Table(name = "author", schema = "bookstore")
public class Author { ... }

How to configure spring to use two different datasources. Getting a NoUniqueBeanDefinitionException for PlatformTransactionManger error

I'm working on spring boot application, which already has a database connection established in its applicationContext.xml file and the necessary transaction manager and vendors etc.
I now need to connect the app to a second database. But I'm having issues with this. In my unit tests the connection is fine and can make simple queries to retrieve data, which is all I need it to do. However when I compile the app into a jar and run it, I get the following error
NoUniqueBeanDefinitionException: No qualifying bean of type "org.springframework.transaction.PlatformTransactionManager" available: expected single matching bean but found 2: transactionManager, transactionManager2
I have spent ages looking up how to solve this, and the suggested fixes I have found here , here and here have not worked.
I have one persistence.xml with two persistence units defined. And in my applicaitonContext.xml I defined two datasources, two transaction managers and two entity Manager Factories. I then use the #persitsencecontext and #Transactional("") annotations to say which persistence unit and managers to use, but I still get an error. I also added in the <qualifier> tag to the app context file, as I saw this as a suggested fix with the #transactional annotation, still no luck.
My code is below, can anyone spot an errors I have made, and why it may not be working as expected
applicationContext.xml
<bean id="dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="..."/>
<property name="username" value="..."/>
<property name="password" value="..."/>
</bean>
<bean id="entityManagerFactory" name="proxy">
<property name="persistenceUnitName" value="proxy" />
<property name="persistenceUnitXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="dataSource" ref="dataSource1" />
<property name="jpaVendorAdapter" ref="hiberanteVendorAdapter" />
<property name="jpaProperties">
<props>
<prop key="hiberante.hbm2ddl.auto">valudate</prop>
</props>
</property>
</bean>
<bean id="hibernateVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />
<property name="database" value="HSQL" />
<property name="showSql" value="true" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<qualifier value="transactionManager1" />
</bean>
<!-- Second datasource -->
<bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="..."/>
<property name="username" value="..."/>
<property name="password" value="..."/>
</bean>
<bean id="entityManagerFactory2" name="proxy">
<property name="persistenceUnitName" value="proxy2" />
<property name="persistenceUnitXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="dataSource" ref="dataSource2" />
<property name="jpaVendorAdapter" ref="hiberanteVendorAdapter2" />
<property name="jpaProperties">
<props>
<prop key="hiberante.hbm2ddl.auto">valudate</prop>
</props>
</property>
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory2" />
<qualifier value="transactionManager2" />
</bean>
<bean id="hibernateVendorAdapter2" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<tx:annotation-driven/>
Implementation
#Repository
#Transactional("transactionManager2")
public class myDaoImpl extends GenericJPADao<Integer, Integer> implements ImyDao {
#PersistenceContext(unitName="proxy2")
protected EntityManager em;
}
SOLUTION
The accepted answer was the correct solution for me, but a few things to note. The beans have to point to their respective entityManagerFactory's and you need to be careful on which bean you set the autowire-candidate="false" on, as I set it on the incorrect one at first, and had transactions rolled back as a result. I think there could be cleaner solution to this, but as a quick fix it works fine
try this :
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" autowire-candidate="false">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

Entity manager has not been injected

I just started working with Spring ROO and I generated my entity classes using the database reverse engineer command. However whenever I try to call one of the CRUD method in the generated entity class, I keep getting this exception :
java.lang.IllegalStateException: Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)
I suspect(by looking at the generated files) that the EntityManager was not injected into the class. Please could you tell me what configuration I am missing?
Here is what my applicationContext.xml looks like
<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
<context:spring-configured/>
<context:component-scan base-package="com.lennartz">
<context:exclude-filter expression=".*_Roo_.*" type="regex"/>
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<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 FROM DUAL"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
And the generated entity files
privileged aspect UserDetail_Roo_Jpa_ActiveRecord {
#PersistenceContext
transient EntityManager UserDetail.entityManager;
public static final EntityManager UserDetail.entityManager() {
EntityManager em = new UserDetail().entityManager;
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
return em;
}
Please let me know if there is something I'm missing.
You must not modify the .aj files, to customize the Roo generated code read http://docs.spring.io/spring-roo/docs/2.0.0.M1/reference/html/#edit-modify-and-customize-the-roo-generated-code
I eventually figured out the problem, it seems context was not being initialized in my application.
I added the following line in my web.xml and it worked
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
If your application is not a web app, I assume initializing the context using ClassPathXmlApplicationContext should work for you.

how to use multiple datasources with spring-data-jpa? [duplicate]

This question already has answers here:
Spring Boot, Spring Data JPA with multiple DataSources
(6 answers)
Closed 4 years ago.
I read all the related questions and tried all of them but still can't make my configuration straight.
I've two databases and i want to use them as datasources in my application.
Here is my context file:
<jee:jndi-lookup id="firstDataSource" jndi-name="java:/comp/env/jdbc/firstDS" expected-type="javax.sql.DataSource" />
<jee:jndi-lookup id="secondDataSource" jndi-name="java:/comp/env/jdbc/secondDS" expected-type="javax.sql.DataSource" />
<bean name="persistenceProvider" class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="thisEntityManagerFactory">
<property name="dataSource" ref="firstDataSource"/>
<property name="packagesToScan" value="com.a.b.first.model"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false" />
<property name="showSql" value="true"/>
<property name="databasePlatform" value= "org.hibernate.dialect.Oracle10gDialect"/>
<property name="database" value="ORACLE"/>
</bean>
</property>
<property name="persistenceUnitName" value="firstPersistenceUnit" />
<property name="persistenceProvider" ref="persistenceProvider"></property>
<property name="jpaProperties">
<value>
hibernate.generate_statistics = true
hibernate.cache.use_second_level_cache = true
hibernate.cache.region.factory_class = org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
hibernate.cache.use_query_cache = true
<!--hibernate.hbm2ddl.auto=create-->
</value>
</property>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="otherEntityManagerFactory">
<property name="dataSource" ref="secondDataSource"/>
<property name="packagesToScan" value="com.a.b.second.model"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false" />
<property name="showSql" value="true"/>
<property name="databasePlatform" value= "org.hibernate.dialect.Oracle10gDialect"/>
<property name="database" value="ORACLE"/>
</bean>
</property>
<property name="persistenceUnitName" value="secondPersistenceUnit" />
<property name="persistenceProvider" ref="persistenceProvider"></property>
<property name="jpaProperties">
<value>
hibernate.generate_statistics = true
hibernate.cache.use_second_level_cache = true
hibernate.cache.region.factory_class = org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
hibernate.cache.use_query_cache = true
<!--hibernate.hbm2ddl.auto=create-->
</value>
</property>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="thisTransactionManager">
<property name="entityManagerFactory" ref="thisEntityManagerFactory"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="otherTransactionManager">
<property name="entityManagerFactory" ref="otherEntityManagerFactory"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<tx:annotation-driven transaction-manager="thisTransactionManager" />
<tx:annotation-driven transaction-manager="otherTransactionManager" />
<jpa:repositories base-package="com.a.b.first.intf" entity-manager-factory-ref="thisEntityManagerFactory" transaction-manager-ref="transactionManager"/>
<jpa:repositories base-package="com.a.b.second.intf" entity-manager-factory-ref="otherEntityManagerFactory" transaction-manager-ref="otherTransactionManager" />
Problem is when i try to use a repository interface which is located under package com.a.b.second.intf, it goes to firstDataSource and throws a SQLSyntaxErrorException with message "ORA-00942: table or view does not exist". Because there is no such table in the first database.
There is a line in tho logs for each EntityManagerFactory, saying
Building JPA container EntityManagerFactory for persistence unit
'default'
And in the next line it prints PersistenceUnitInfo for this EntityManagerFactory. The "Non JTA datasource" property of the PersistenceUnitInfo is same for both EntityManagerFactories. I guess that means both persistence units uses the same datasource.
What am i missing?
Thanks.
In your service layer you should have something like this:
#Service
#Transactional("thisTransactionManager")
public class ThisService{
#Autowired
private com.a.b.first.intf.Repo1 repo1;
}
#Service
#Transactional("otherEntityManagerFactory")
public class OtherService{
#Autowired
private com.a.b.second.intf.Repo1 repo1;
}
This way, when you call a service method, the TransactionInterceptor can load the appropriate transaction manager, associated to the EntityManagerFactory you want to operate with.

Configuring apache dbcp PoolingDataSource with Spring

Tried to follow the pattern on apache dbcp examples, I understand everything except how and where the database properties come from and in which bean they have to be placed in application context.
I used Spring Data Source instead, but as I recall I configured it in hurry and I remember having difficulties with configuring the original dataSource provided by apache dbcp itself. So I happen to have time to face the problem and fulfill the original intent of using PoolingDataSource.
The reason I used Spring implementation is because it provides means of setting up the parameters to connect to database.
http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/jdbc/datasource/DriverManagerDataSource.html
According to http://commons.apache.org/dbcp/apidocs/org/apache/commons/dbcp/PoolingDataSource.html
There are no methods to populate configuration like url or load driver.
I tried to track it through the object pools etc. , but got really lost.
Replying upfront: Yes, I don't want to use apache basicDataSource.
So now I am returning to the problem and can't really understand where to fetch the parameters? Driver? Url? It seems that url, pw and username are set on connection factory. But where to fetch postgresql driver to be loaded?
Please help to complete the configuration.
(using spring for configuration)
<!-- the one I want to use now -->
<bean id="dataSource" class="org.apache.commons.dbcp.PoolingDataSource">
<constructor-arg><ref bean="pool"/></constructor-arg>
</bean>
<!-- the one I used before as a workaround
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql:postgres"/>
<property name="username" value="magicUserName"/>
<property name="password" value="magicPassword"/>
</bean> -->
<bean id="pool" class="org.apache.commons.pool.impl.GenericObjectPool">
<property name="minEvictableIdleTimeMillis"><value>300000</value </property>
<property name="timeBetweenEvictionRunsMillis"><value>60000</value </property>
</bean>
<bean id="dsConnectionFactory" class="org.apache.commons.dbcp.DataSourceConnectionFactory">
<constructor-arg><ref bean="dataSource"/></constructor-arg>
</bean>
<bean id="poolableConnectionFactory" class="org.apache.commons.dbcp.PoolableConnectionFactory">
<constructor-arg index="0"><ref bean="dsConnectionFactory"/ </constructor-arg>
<constructor-arg index="1"><ref bean="pool"/></constructor-arg>
<constructor-arg index="2"><null/></constructor-arg>
<constructor-arg index="3"><null/></constructor-arg>
<constructor-arg index="4"><value>false</value></constructor-arg>
<constructor-arg index="5"><value>true</value></constructor-arg>
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
</beans>
I believe we are interested just in the first two, but I included everything just in case.
Seems to be there are many people using workarounds:
http://forum.springsource.org/showthread.php?10772-How-do-I-create-a-org-apache-commons-dbcp-PoolableConnection
You can config as below:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="<put database connection url here>" />
<property name="username" value="XXXXXX" />
<property name="password" value="XXXXXXXX" />
<property name="driverClassName" value="<database driver here>" />
</bean>
<bean id="pool" class="org.apache.commons.pool.impl.GenericObjectPool">
<property name="minEvictableIdleTimeMillis"><value>300000</value></property>
<property name="timeBetweenEvictionRunsMillis"><value>60000</value></property>
</bean>
<bean id="dsConnectionFactory" class="org.apache.commons.dbcp.DataSourceConnectionFactory">
<constructor-arg><ref bean="dataSource"/></constructor-arg>
</bean>
<bean id="poolableConnectionFactory" class="org.apache.commons.dbcp.PoolableConnectionFactory">
<constructor-arg index="0"><ref bean="dsConnectionFactory"/></constructor-arg>
<constructor-arg index="1"><ref bean="pool"/></constructor-arg>
<constructor-arg index="2"><null/></constructor-arg>
<constructor-arg index="3"><null/></constructor-arg>
<constructor-arg index="4"><value>false</value></constructor-arg>
<constructor-arg index="5"><value>true</value></constructor-arg>
</bean>
<bean id="pooledDS" class="org.apache.commons.dbcp.PoolingDataSource"
depends-on="poolableConnectionFactory">
<constructor-arg><ref bean="pool"/></constructor-arg>
</bean>
And you can use "pooledDS" (PoolingDataSource) the same any orther DataSource.
Ortherwise, i think you should simply use BacsicDataSource, you still can config number of connections in pool by "initialSize" and "maxActive":
<bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="removeAbandoned" value="true"/>
<property name="initialSize" value="10" />
<property name="maxActive" value="50" />
</bean>

Categories

Resources