Spring Multi Datasource with entity manager - java

I am facing problem in multi data source connection with spring, one of the transaction is working, but other one is not working. please help.
***********Data Source 1 start************
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="database1.ds" />
<property name="persistenceUnitName" value="database1" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="persistenceXmlLocation" value="classpath:jpa-persistence.xml" />
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="false" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory" />
***********Data Source 1 end************
***********Data Source 2 start************
<bean id="entityManagerFactory2"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="database2.ds" />
<property name="persistenceUnitName" value="database2" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter2" />
<property name="persistenceXmlLocation" value="classpath:jpa-persistence.xml" />
</bean>
<bean id="jpaVendorAdapter2
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="false" />
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory2" />
***********Data Source 2 end************
<context:component-scan base-package="com.wmi.lakshya" annotation-config="true" scope-resolver="org.springframework.context.annotation.Jsr330ScopeMetadataResolver"/>
<tx:annotation-driven />
<cache:annotation-driven />
Entity Manager class
#Repository
#Scope("singleton")
public class EntityManagerImpl implements EntityManagerGenerator {
#PersistenceContext(unitName = "database1",type=PersistenceContextType.EXTENDED)
private EntityManager entityManager;
#PersistenceContext(unitName = "database2",type=PersistenceContextType.EXTENDED)
private EntityManager entityManager2;
#Override
public EntityManager getEntityManager() {
try {
if (isUser1()) {
return entityManager;
}
return entityManager2;
} catch (Exception e) {
return entityManager;
}
}
}
#Transactional(value ="transactionManager")
public Query createNativeQuery(String sqlString) {
return entityManager.createNativeQuery(sqlString);
}
#Transactional(value ="transactionManager2")
public Query createNativeQuery1(String sqlString) {
return entityManager1.createNativeQuery(sqlString);
}
javax.persistence.TransactionRequiredException: Executing an
update/delete query
#Component
#Scope("prototype")
public class UserDAO extends AbstractDAO<User> {
/**
*
*/
private static final Logger LOGGER = Logger.getLogger(UserDAO.class);
/**
*
*/
protected UserDAO() {
super(User.class);
}
public void resetFailAttempts(String userName){
// em is entity manager class
em.createNativeQuery("update OMS_USER_MASTER set fail_attempts = 0 where login_id = :loginId ")
.setParameter(QueryParameters.LOGIN_ID, userName)
.executeUpdate();
}
}
Datasource is switched based on the condition, when connecting with datasource 1 is working, but not for datasource2.

Related

Spring with two transaction managers and one within another

I have two transaction managers defined in my context file as follows
<tx:annotation-driven transaction-manager="firstTransactionManager" />
<bean id="secondDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="---" />
<property name="url" value="datasource1" />
<property name="username" value="----" />
<property name="password" value="----" />
</bean>
<bean id="firstTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="firstDataSource" />
<qualifier value="firstTxManager"/>
</bean>
<bean id="secondTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="secondDataSource" />
<qualifier value="secondTxManager"/>
</bean>
<bean id="firstDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="---" />
<property name="url" value="datasource2" />
<property name="username" value="---" />
<property name="password" value="---" />
</bean>
And I my class definitions are as follows
#Transactional("firstTransactionManager")
public class JdbcMain {
#Autowired
private static DataSource dataSource;
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public static void main(String args[]){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
TransactionExample example = (TransactionExample) ctx.getBean("transExample");
example.create();
}
}
And my example class is as follows:
#Transactional("secondTransactionManager")
public void create(DataSource dataSource2) {
try {
this.jdbcTemplate = new JdbcTemplate(dataSource2);
String sql = "insert into testtable values (?,?)";
getJdbcTemplate().update(sql,1,"1244343");
String marksSql="insert into testtable values (?,?)";
int i=2/0; //added to depict roll back behaviour of the transaction when exception occurs
getJdbcTemplate().update(marksSql,2,"sujay");
System.out.println("transaction committed");
} catch (RuntimeException e) {
throw e;
}
}
But the second transaction manager doesn't seem to work and the transaction is not rolled back (The first insert is executed). Can you provide me an idea.

Could not get JDBC Connection - Connection Closing Issue

On production environment I got following error.
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Cannot create PoolableConnectionFactory (The Network Adapter could not establish the connection)
When I connect through toad, it said ORA-12541 no listener error. The issue resolved after restart of linstener.
But the actual issue may be that lot of connections opened by the web application and it is not closing that. Following are my code and configuration.
I am using EcllipseLink, dbcp2 for connections
<persistence-unit name="persistance-unit" transaction-type="RESOURCE_LOCAL">
<class>com.company.model.Characteristic</class>
...
<!--more classes -->
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.weaving" value="false"/>
</properties>
</persistence-unit>
dbcp2 settings
<bean id="datasource" class="org.apache.commons.dbcp2.BasicDataSource">
<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="maxIdle" value="10" />
<property name="maxTotal" value="200" />
<property name="maxWaitMillis" value="60000" />
<property name="validationQuery" value="select 1 from dual" />
<property name="validationQueryTimeout" value="10" />
<property name="testOnBorrow" value="true" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<property name="minEvictableIdleTimeMillis" value="60000" />
<property name="numTestsPerEvictionRun" value="5" />
<property name="defaultAutoCommit" value="true" />
</bean>
Connection Factory
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="persistance-unit"/>
<property name="dataSource" ref="datasource"/>
<property name="jpaVendorAdapter">
<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="database" value="ORACLE"/>
</bean>
</property>
</bean>
Transaction Management
Abstract GenericDao
public abstract class GenericDao<T> implements IGenericDao<T> {
#PersistenceContext
protected EntityManager entityManager
private Class<T> type
public GenericDao() {
Type t = getClass().getGenericSuperclass()
ParameterizedType pt = (ParameterizedType) t
type = (Class) pt.getActualTypeArguments()[0]
}
#Override
public T save(final T t) {
this.entityManager.persist(t)
return t
}
public def saveObj(def t) {
try {
this.entityManager.persist(t)
}catch(e){
log.info("Error occured: ", e)
}
return t
}
#Override
public void delete(final Object id) {
this.entityManager.remove(this.entityManager.getReference(type, id))
}
#Override
public T find(final Object id) {
return (T) this.entityManager.find(type, id)
}
#Override
public T update(final T t) {
return this.entityManager.merge(t)
}
#Override
public def executeNamedQuery(String namedQueryName, Map<String, Object> queryParams)
{
List results = null
try {
Query query = entityManager.createNamedQuery(namedQueryName)
if (queryParams) {
addPrametersToQuery(query, queryParams)
}
results = query.getResultList()
} catch (NoResultException e) {
} catch (Exception e) {
log.error("Error occured: ", e)
throw e
}
return results
}
}
Dao component using that Generic Dao
#Component("characteristicDao")
class CharacteristicDao extends GenericDao<Characteristic> implements ICharacteristicDao {
public def getCharacteristics(String name){
log.info("Entering getCharacteristics")
Characteristic characteristic = (PrmCharacteristic) executeQueryWithSingleResult("select b from Characteristic b where b.name=:name", [name:name])
log.info("Exiting getCharacteristics")
return characteristic
}
}
I use CharacteristicDao component to interact with database. Similarly I have other dao also. I have just given one example.
I use #Transactional in service for the transaction. Any master can help me please what I am doing wrong.

Hibernate JPA interceptor doesn't get call

The setup I have an old project that is stuck to jdk 1.5, thus spring and hibernate versions are also the maximum possible to support this version of java. Hibernate is 3.3.2.GA and spring is 3.1.1.RELEASE. Setup is the following:
<persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
<mapping-file>persistence-query.xml</mapping-file>
...
<properties>
<property name="hibernate.max_fetch_depth" value="3" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.ejb.interceptor" value="com.myproj.common.dao.AuditInterceptor"/>
</properties>
</persistence-unit>
application context:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:component-scan base-package="..."/>
<tx:annotation-driven transaction-manager="transactionManager" />
<aop:aspectj-autoproxy/>
<bean id="applicationContextProvder" class="com.myproj.common.utils.ApplicationContextProvider"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:persistence.xml" />
<property name="persistenceUnitName" value="myUnit" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<!-- Local transaction management -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
and my interceptor:
#Component
public class AuditInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = 98658932451L;
#Autowired
private JdbcTemplate jdbcTemplate;
public void afterTransactionBegin(Transaction tx) {
if (user != null) {
jdbcTemplate.execute("call ah_audit_pkg.SetAudit('test')");
super.afterTransactionBegin(tx);
}
}
}
I run a junit to test that interceptor is getting called and it is not. In debug mode, I am able to see this:
Any help is appreciated! Why my intercetprot is not getting called.
Edit:
I also tried the interceptor to override the afterTransactionBegin but it didn't help.
I ended up with the following solution:
I have my entityt that extends from a superclass mapped entity:
#Entity
#Table(name = "my_table")
public class MyTable extends AuditInfo
The AuditInfo entity has the following mapping:
#MappedSuperclass
public abstract class AuditInfo implements Serializable {
...
#PrePersist
void onCreate() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is stored
}
#PreUpdate
void onPersist() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is updated
}
#PreRemove
void onRemove() throws SQLException {
//this empty method is needed for AOP to trigger the audit information insert before entity is removed
}
}
And the Aspect class:
#Aspect
#Component
public class MyAspect {
#Before("execution(* com.mypackage.entities.AuditInfo.on*(..))")
public void setAuditHistory(JoinPoint jp){
final AuditInfo info = ((AuditInfo)jp.getThis());
JdbcTemplate jdbcTemplate = ApplicationContextProvider.getApplicationContext().getBean(JdbcTemplate.class);
jdbcTemplate.execute(new CallableStatementCreator() {
public CallableStatement createCallableStatement(Connection conn) throws SQLException {
CallableStatement stmt = conn.prepareCall("begin ah_audit_pkg.SetAudit(?,?); end;");
stmt.setString(1, info.getAuditUser());
if(info.getAuditLocation() != null && info.getAuditLocation().trim().length() !=0) {
stmt.setString(2, info.getAuditLocation());
} else {
stmt.setString(2, info.getAuditUser());
}
return stmt;
}
}, new CallableStatementCallback<Object>() {
public Object doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
return cs.executeUpdate();
}
});
}
}
It is to be noted that the Spring beans are extracted from the context and not autowired - this is because AOP is a singleton class in spring implementation, and none of the autowired beans will be ever instantiated even if they are available in the context. So I had to manually retrieve them for later usage.

Spring Batch 3.0.3: How to set custom params for JdbcPagingItemReader query?

What would be the best way to set custom parameters to JdbcPagingItemReader query?
My custom JdbcPagingItemReader implementation:
public class CustomItemReader extends JdbcPagingItemReader<Long> {
public CustomItemReader(DataSource dataSource) throws Exception {
SqlPagingQueryProviderFactoryBean queryProvider = new SqlPagingQueryProviderFactoryBean();
queryProvider.setDataSource(dataSource);
queryProvider.setSelectClause("SELECT t1.id");
queryProvider.setFromClause("FROM table1 t1 LEFT JOIN table2 t2 ON t2.fk_table1_id = t1.id");
queryProvider.setWhereClause("WHERE (t1.col1 = :param1) AND ((t2.id IS NULL) OR (t2.col3 = :param2))");
queryProvider.setSortKey("t1.id");
setDataSource(dataSource);
setFetchSize(10);
setRowMapper(new RowMapper<Long>() {
#Override
public Long mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getLong(1);
}
});
setQueryProvider(queryProvider.getObject());
}
}
To pass parameters from the job's ExecutionContext to the JdbcPagingItemReader, you'd configure the writer as follows:
<bean id="itemReader" class="org.springframework.batch.item.database.JdbcPagingItemReader" scope="step">
<property name="dataSource" ref="dataSource" />
<property name="rowMapper">
<bean class="MyRowMapper" />
</property>
<property name="queryProvider">
<bean class="org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="sortKeys">
<map>
<entry key="t1.id" value="ASCENDING"/>
</map>
</property>
<property name="selectClause" value="SELECT t1.id" />
<property name="fromClause" value="FROM table1 t1 LEFT JOIN table2 t2 ON t2.fk_table1_id = t1.id" />
<property name="whereClause" value=""WHERE (t1.col1 = :param1) AND ((t2.id IS NULL) OR (t2.col3 = :param2))" />
</bean>
</property>
<property name="pageSize" value="10" />
<property name="parameterValues">
<map>
<entry key="param1" value="#{jobExecutionContext[param1]}" />
<entry key="param2" value="#{jobExecutionContext[param2]}" />
</map>
</property>
</bean>
You can view a configuration like this in action in the Spring Batch examples here: https://github.com/spring-projects/spring-batch/tree/master/spring-batch-samples

Spring batch integration

I am looking for a guidance/solution with Spring batch integration. I have a directory to which external application will send xml files. My application should read the file content and move the file to another directory.
The application should be able to process the files in parallel.
Thanks in advance.
You can use Spring Integration ftp / sftp combined with Spring Batch:
1.Spring Integration Ftp Configuration :
<bean id="ftpClientFactory"
class="org.springframework.integration.ftp.session.DefaultFtpSessionFactory">
<property name="host" value="${host.name}" />
<property name="port" value="${host.port}" />
<property name="username" value="${host.username}" />
<property name="password" value="${host.password}" />
<property name="bufferSize" value="100000"/>
</bean>
<int:channel id="ftpChannel" />
<int-ftp:outbound-channel-adapter id="ftpOutbound"
channel="ftpChannel" remote-directory="/yourremotedirectory/" session-factory="ftpClientFactory" use-temporary-file-name="false" />
2.Create your reader and autowire a service to provide your items if needed :
#Scope("step")
public class MajorItemReader implements InitializingBean{
private List<YourItem> yourItems= null;
#Autowired
private MyService provider;
public YourItem read() {
if ((yourItems!= null) && (yourItems.size() != 0)) {
return yourItems.remove(0);
}
return null;
}
//Reading Items from Service
private void reloadItems() {
this.yourItems= new ArrayList<YourItem>();
// use the service to provide your Items
if (yourItems.isEmpty()) {
yourItems= null;
}
}
public MyService getProvider() {
return provider;
}
public void setProvider(MyService provider) {
this.provider = provider;
}
#Override
public void afterPropertiesSet() throws Exception {
reloadItems();
}
}
3. Create Your Own Item Processor
public class MyProcessor implements
ItemProcessor<YourItem, YourItem> {
#Override
public YourItem process(YourItem arg0) throws Exception {
// Apply any logic to your Item before transferring it to the writer
return arg0;
}
}
4. Create Your Own Writer :
public class MyWriter{
#Autowired
#Qualifier("ftpChannel")
private MessageChannel messageChannel;
public void write(YourItem pack) throws IOException {
//create your file and from your Item
File file = new File("the_created_file");
// Sending the file via Spring Integration Ftp Channel
Message<File> message = MessageBuilder.withPayload(file).build();
messageChannel.send(message);
}
5.Batch Configuration :
<bean id="dataSourcee"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="" />
<property name="url" value="" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="dataSource" ref="dataSourcee" />
<property name="transactionManager" ref="transactionManagerrr" />
<property name="databaseType" value="" />
</bean>
<bean id="transactionManagerrr"
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
6.Another ApplicationContext file to Configure Your Job :
<context:annotation-config />
<bean id="provider" class="mypackage.MyService" />
<context:component-scan base-package="mypackage" />
<bean id="myReader" class="mypackage.MyReader"
<property name="provider" ref="provider" />
</bean>
<bean id="myWriter" class="mypackage.MyWriter" />
<bean id="myProcessor" class="mypackage.MyProcessor" />
<bean id="mReader"
class="org.springframework.batch.item.adapter.ItemReaderAdapter">
<property name="targetObject" ref="myReader" />
<property name="targetMethod" value="read" />
</bean>
<bean id="mProcessor"
class="org.springframework.batch.item.adapter.ItemProcessorAdapter">
<property name="targetObject" ref="myProcessor" />
<property name="targetMethod" value="process" />
</bean>
<bean id="mWriter"
class="org.springframework.batch.item.adapter.ItemWriterAdapter">
<property name="targetObject" ref="myWriter" />
<property name="targetMethod" value="write" />
</bean>
<batch:job id="myJob">
<batch:step id="step01">
<batch:tasklet>
<batch:chunk reader="mReader" writer="mWriter"
processor="mProcessor" commit-interval="1">
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="myRunScheduler" class="mypackage.MyJobLauncher" />
<task:scheduled-tasks>
<task:scheduled ref="myJobLauncher" method="run"
cron="0 0/5 * * * ?" />
<!-- this will maker the job runs every 5 minutes -->
</task:scheduled-tasks>
7.Finally Configure A launcher to launch your job :
public class MyJobLauncher {
#Autowired
private JobLauncher jobLauncher;
#Autowired
#Qualifier("myJob")
private Job job;
public void run() {
try {
String dateParam = new Date().toString();
JobParameters param = new JobParametersBuilder().addString("date",
dateParam).toJobParameters();
JobExecution execution = jobLauncher.run(job, param);
execution.stop();
} catch (Exception e) {
e.printStackTrace();
}
}

Categories