Oracle AQ JMS with XA transaction throwing NullPointException while fetching connection - oracle

I am trying to use Oracle AQ supporting XA transaction since i have other datasource like Active MQ and DB involved in the transaction. When i tried to post to oracle aq queue1. it is failing with a NullPointerException while getting the XAconnection from the datasource.
I am using oracle ojdbc6,aqapi.jar of 11.2 version
Snippet of my camel blueprint with my bean defintion is given below
<reference id="transactionManager" interface="javax.transaction.TransactionManager" />
<reference id="recoverableTxManager" interface="org.apache.geronimo.transaction.manager.RecoverableTransactionManager" availability="mandatory" />
<reference id="platformTxManager" interface="org.springframework.transaction.PlatformTransactionManager" availability="mandatory"/>
<bean id="oracleXaDataSource" class="oracle.jdbc.xa.client.OracleXADataSource" destroy-method="close">
<property name="user" value="dbuser" />
<property name="password" value="dbpassword" />
<property name="URL" value="dburl" />
</bean>
<bean id="connectionFactoryOracleAQ" class="oracle.jms.AQjmsFactory" factory-method="getXAQueueConnectionFactory">
<argument value="oracleXaDataSource" />
</bean>
<bean id="oracleaqJcaPooledConnectionFactory" class="org.apache.activemq.jms.pool.JcaPooledConnectionFactory" init-method="start"
destroy-method="stop">
<property name="idleTimeout" value="0"/>
<property name="name" value="aq.default"/>
<property name="maxConnections" value="1"/>
<property name="connectionFactory" ref="connectionFactoryOracleAQ"/>
<property name="transactionManager" ref="transactionManager"/>
</bean>
<bean id="resourceManager-AQ" class="org.apache.activemq.jms.pool.GenericResourceManager"
init-method="recoverResource">
<property name="connectionFactory" ref="connectionFactoryOracleAQ"/>
<property name="transactionManager" ref="recoverableTxManager"/>
<property name="resourceName" value="aq.default"/>
<property name="userName" value="${primary.datasource.user}"/>
<property name="password" value="${primary.datasource.password}"/>
</bean>
<bean id="oracleaqJmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="oracleaqJcaPooledConnectionFactory"/>
<property name="transactionManager" ref="platformTxManager"/>
<property name="transacted" value="false"/>
</bean>
<bean id="oracleaq" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="oracleaqJmsConfig" />
</bean>
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="route1">
<from uri="vm:route1" />
<log message="Message to the oracle Aq:queue1-- ${body}" />
<to uri="oracleaq:queue:queue1?jmsMessageType=Text" pattern="InOnly"/>
</route>
</camelContext>
Could you please help me identifying what is the issue. The exception is given l
2017-02-27 12:14:11,613 | WARN | loyer-4-thread-1 | PooledConnectionFactory | 9037 - org.apache.activemq.activemq-osgi - 5.11.0.redhat-621084 | Create pooled connection during start failed. This exception will be ignored.
javax.jms.JMSException: Error while attempting to add new Connection to the pool
at org.apache.activemq.jms.pool.PooledConnectionFactory.createJmsException(PooledConnectionFactory.java:267)
at org.apache.activemq.jms.pool.PooledConnectionFactory.createConnection(PooledConnectionFactory.java:226)
at org.apache.activemq.jms.pool.PooledConnectionFactory.createConnection(PooledConnectionFactory.java:205)
at org.apache.activemq.jms.pool.PooledConnectionFactory.start(PooledConnectionFactory.java:291)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[:1.7.0_25]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)[:1.7.0_25]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)[:1.7.0_25]
at java.lang.reflect.Method.invoke(Method.java:606)[:1.7.0_25]
at org.apache.aries.blueprint.utils.ReflectionUtils.invoke(ReflectionUtils.java:299)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BeanRecipe.invoke(BeanRecipe.java:956)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BeanRecipe.runBeanProcInit(BeanRecipe.java:712)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BeanRecipe.internalCreate2(BeanRecipe.java:824)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BeanRecipe.internalCreate(BeanRecipe.java:787)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.di.AbstractRecipe$1.call(AbstractRecipe.java:79)[15:org.apache.aries.blueprint.core:1.4.4]
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)[:1.7.0_25]
at java.util.concurrent.FutureTask.run(FutureTask.java:166)[:1.7.0_25]
at org.apache.aries.blueprint.di.AbstractRecipe.create(AbstractRecipe.java:88)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintRepository.createInstances(BlueprintRepository.java:247)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintRepository.createAll(BlueprintRepository.java:183)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintContainerImpl.instantiateEagerComponents(BlueprintContainerImpl.java:682)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintContainerImpl.doRun(BlueprintContainerImpl.java:377)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintContainerImpl.run(BlueprintContainerImpl.java:269)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintExtender.createContainer(BlueprintExtender.java:294)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintExtender.createContainer(BlueprintExtender.java:263)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.blueprint.container.BlueprintExtender.modifiedBundle(BlueprintExtender.java:253)[15:org.apache.aries.blueprint.core:1.4.4]
at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$Tracked.customizerModified(BundleHookBundleTracker.java:500)[9:org.apache.aries.util:1.1.0]
at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$Tracked.customizerModified(BundleHookBundleTracker.java:433)[9:org.apache.aries.util:1.1.0]
at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$AbstractTracked.track(BundleHookBundleTracker.java:725)[9:org.apache.aries.util:1.1.0]
at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$Tracked.bundleChanged(BundleHookBundleTracker.java:463)[9:org.apache.aries.util:1.1.0]
at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$BundleEventHook.event(BundleHookBundleTracker.java:422)[9:org.apache.aries.util:1.1.0]
at org.apache.felix.framework.util.SecureAction.invokeBundleEventHook(SecureAction.java:1127)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.util.EventDispatcher.createWhitelistFromHooks(EventDispatcher.java:696)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:484)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.Felix.fireBundleEvent(Felix.java:4429)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.Felix.startBundle(Felix.java:2100)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:976)[org.apache.felix.framework-4.4.1.jar:]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:963)[org.apache.felix.framework-4.4.1.jar:]
at io.fabric8.agent.service.Agent$BaseDeployCallback.startBundle(Agent.java:482)[86:io.fabric8.fabric-agent:1.2.0.redhat-621084]
at io.fabric8.agent.service.Deployer$3.call(Deployer.java:935)[86:io.fabric8.fabric-agent:1.2.0.redhat-621084]
at io.fabric8.agent.service.Deployer$3.call(Deployer.java:930)[86:io.fabric8.fabric-agent:1.2.0.redhat-621084]
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)[:1.7.0_25]
at java.util.concurrent.FutureTask.run(FutureTask.java:166)[:1.7.0_25]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)[:1.7.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)[:1.7.0_25]
at java.lang.Thread.run(Thread.java:724)[:1.7.0_25]
Caused by: oracle.jms.AQjmsException: Error creating the db_connection
at oracle.jms.AQjmsDBConnMgr.getConnection(AQjmsDBConnMgr.java:625)
at oracle.jms.AQjmsDBConnMgr.<init>(AQjmsDBConnMgr.java:458)
at oracle.jms.AQjmsXAConnection.<init>(AQjmsXAConnection.java:129)
at oracle.jms.AQjmsXAConnectionFactory.createXAConnection(AQjmsXAConnectionFactory.java:212)
at org.apache.activemq.jms.pool.XaPooledConnectionFactory.createConnection(XaPooledConnectionFactory.java:79)
at org.apache.activemq.jms.pool.PooledConnectionFactory$1.makeObject(PooledConnectionFactory.java:108)
at org.apache.activemq.jms.pool.PooledConnectionFactory$1.makeObject(PooledConnectionFactory.java:88)
at org.apache.commons.pool.impl.GenericKeyedObjectPool.addObject(GenericKeyedObjectPool.java:1748)
at org.apache.activemq.jms.pool.PooledConnectionFactory.createConnection(PooledConnectionFactory.java:222)
... 43 more
Caused by: java.lang.NullPointerException
at oracle.jms.AQjmsGeneralDBConnection.getProviderKey(AQjmsGeneralDBConnection.java:99)
at oracle.jms.AQjmsGeneralDBConnection.<init>(AQjmsGeneralDBConnection.java:77)
at oracle.jms.AQjmsDBConnMgr.getConnection(AQjmsDBConnMgr.java:541)
... 51 more

I think i got what the issue is. The aqapi.jar that i am using from oracle 11.2 client has got the bug. The class AqjmsGeneralDBConnection is not initializing the m_dbConn object for the QAConnection (constructor with XAConnection as argument) and trying to access the getURL() on the m_dbConn object which is null. I tried using the aqapi13.jar from 10.2.0 version and it works
AQjmsGeneralDBConnection(AQjmsDBConnMgr paramAQjmsDBConnMgr, Connection paramConnection, boolean paramBoolean1, boolean paramBoolean2)
throws JMSException
{
this.m_connMgr = paramAQjmsDBConnMgr;
this.m_dbConn = paramConnection;
this.m_isExternal = paramBoolean1;
this.m_force = paramBoolean2;
this.providerKey = getProviderKey();
}
AQjmsGeneralDBConnection(AQjmsDBConnMgr paramAQjmsDBConnMgr, XAConnection paramXAConnection, boolean paramBoolean1, boolean paramBoolean2)
throws JMSException
{
this.m_connMgr = paramAQjmsDBConnMgr;
this.m_xaConn = paramXAConnection;
this.m_isExternal = paramBoolean1;
this.m_force = paramBoolean2;
this.providerKey = getProviderKey();
}
private String getProviderKey()
throws JMSException
{
try
{
OracleConnection localOracleConnection = (OracleConnection)this.m_dbConn;
**String str1 = localOracleConnection.getURL();**
int i = str1.indexOf('#');
String str2;
if (i < 0)
{
if ((!"jdbc:oracle:kprb:".equals(str1)) && (!"jdbc:default:connection:".equals(str1))) {
AQjmsError.throwEx(112);
}
str2 = "jdbc:oracle:kprb:";
}
else
{
str2 = str1.substring(i);
}
return str2.toUpperCase();
}
catch (SQLException localSQLException)
{
throw new AQjmsException(localSQLException);
}
}

Related

Spring Batch & Azure SQL Server : SQL Server did not return a response. The connection has been closed

I have a spring batch application that uses Azure SQL server, it runs without any issues and updates the Database for a most part however I am getting the following error occasionally
what does it mean? how to handle this?
Note: this is a long running job executes for more than 2hrs. The above error reported after ~1.45hrs.
I am reading the data from CSV file using FlatfileReader & writing into Azure SQL Server using ItemWriter as mentioned below
public class StoreWriter implements ItemWriter<List<Store>> {
Logger logger = Logger.getLogger(StoreWriter.class);
private HibernateItemWriter<Store> hibernateItemWriter;
public StoreWriter(HibernateItemWriter<Store> hibernateItemWriter) {
this.hibernateItemWriter = hibernateItemWriter;
}
#Override
public void write(List<? extends List<Store>> items) throws Exception {
for (List<Store> Store : items) {
hibernateItemWriter.write(Store);
}
logger.info(String.format("Store Processing Completed %s", new LocalDateTime()));
}
}
Below is my Hibernate configuration
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager" lazy-init="true">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- HikariCP Database bean -->
<bean id="demoDataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig" />
</bean>
<!-- HikariConfig config that is fed to above dataSource -->
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="maximumPoolSize" value="50" />
<property name="idleTimeout" value="30000" />
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="url" value="jdbc:sqlserver://demo.database.windows.net:1433;database=sqldb;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;" />
<property name="username" value="user1" />
<property name="password" value="p#ssword1" /
</bean>
<bean class="org.springframework.batch.core.scope.StepScope" />
Please try using the annotation "#Transactional (propagation = Propagation.REQUIRES_NEW)" on the method where the records were committed.

Bean property 'entityManager' is not writable or has an invalid setter method (using Spring and Hibernate)

Spring and hibernate are both new tools for me and I struggle a bit using both at the same time.
spring.xml :
<bean id="my.supervisionFramesProcess" class="supervision.frames.SupervisionFramesProcess"
init-method="startup" destroy-method="shutdown">
<property name="SupervisionDAO">
<bean class="supervision.dao.jpa.JpaSupervisionDao">
<property name="entityManager" ref="my.entity-manager-factory" />
</bean>
</property>
</bean>
<bean id="my.dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://XXXX/supervision?autoReconnect=true" />
<property name="username" value="***" />
<property name="password" value="***" />
<property name="maxIdle" value="5" />
<property name="maxActive" value="100" />
<property name="maxWait" value="30000" />
<property name="testOnBorrow" value="true" />
<property name="validationQuery" value="SELECT 1" />
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"></bean>
<bean id="my.entity-manager-factory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml" />
<property name="dataSource" ref="my.dataSource" />
<property name="persistenceUnitName" value="SUPERVISION-1.0" />
</bean>
JpaSupervisionDao.xml :
#PersistenceContext(unitName = "SUPERVISION-1.0")
private EntityManager entityManager;
public JpaSupervisionDao() {
if (logger.isDebugEnabled())
logger.debug("New instance DAO : " + this);
}
protected void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
protected EntityManager getEntityManager() {
return entityManager;
}
#Override
public SupervisionDbObject selectSupervisionDbObject(SupervisionDbObject supervision) {
Query query = getEntityManager().createQuery(SELECT_SUPERVISION);
}
persistence.xml :
<persistence-unit name="SUPERVISION-1.0">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>supervision.dao.SupervisionDbObject</class>
</persistence-unit>
Using JDBC, my DataSource can be instanciated and is fully working but using Hibernate and the entityManager, i only get an error :
Bean property 'entityManager' is not writable or has an invalid setter method.
I have tried to use the EntityManagerFactory object instead but the same error occurs.
Can someone help me out ?
The addition of the <context:annotation-config/> fixed my issue thanks to M. Deinum's answer.
If this can help someone else, I also had an issue with an import, I was importing
org.hibernate.annotations.Entity instead of javax.persistence.Entity.

No value for key [org.springframework.ldap.core.support.LdapContextSource#27bd27bd] bound to thread [main]

I'm trying to implement LDAP transaction using Spring.I have configured the spring xml based on the spring Doc, but while running the program i'm getting below mentioned error:
java.lang.IllegalStateException: No value for key [org.springframework.ldap.core.support.LdapContextSource#27bd27bd] bound to thread [main]
at org.springframework.transaction.support.TransactionSynchronizationManager.unbindResource(TransactionSynchronizationManager.java:199)
at org.springframework.transaction.compensating.support.AbstractCompensatingTransactionManagerDelegate.doCleanupAfterCompletion(AbstractCompensatingTransactionManagerDelegate.java:122)
at org.springframework.ldap.transaction.compensating.manager.ContextSourceTransactionManager.doCleanupAfterCompletion(ContextSourceTransactionManager.java:135)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager.java:1011)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:877)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:411)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:114)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy11.createUser(Unknown Source)
Note:I'm trying to rollback LDAP as well as DB.
Code snippet:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.apps.ldap.manager.UserManger;
import com.apps.ldap.model.UserBean;
public class SpringFrameworkLDAPClient {
private static ApplicationContext context = null;
public static void main(String[] args) {
try {
context = new ClassPathXmlApplicationContext("conf/springldap.xml");
UserManger userservice = (UserManger)context.getBean("userManger");
UserBean userbean = new UserBean();
userbean.setCommonName("Santhosh5");
userbean.setLastName("Rajendran5");
userbean.setEmail("rsanthoshkumarr#gmail.com");
userbean.setFirstName("Santhosh5");
userbean.setUserID("Santhosh5");
userservice.createuser(userbean);
} catch (Exception e) {
System.out.println("Error occured " + e);
e.printStackTrace();
}
}
}
UserService
#Transactional
public void createuser(UserBean contactDTO) {
Attributes personAttributes = new BasicAttributes();
BasicAttribute personBasicAttribute = new BasicAttribute("objectclass");
personBasicAttribute.add("person");
personAttributes.put(personBasicAttribute);
personAttributes.put("cn", contactDTO.getCommonName());
personAttributes.put("sn", contactDTO.getLastName());
DistinguishedName newContactDN = new DistinguishedName("ou=users");
newContactDN.add("cn", contactDTO.getCommonName());
ldapTemplate.bind(newContactDN, null, personAttributes);
}
XML:
<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://xxxx:389" />
<property name="base" value="dc=xxx" />
<property name="userDn" value="cn=xxx" />
<property name="password" value="xxx" />
</bean>
<bean id="contextSource" class="org.springframework.ldap.transaction.compensating.manager.TransactionAwareContextSourceProxy">
<constructor-arg ref="contextSourceTarget" />
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<bean id="transactionManager" class="org.springframework.ldap.transaction.compensating.manager.ContextSourceTransactionManager">
<property name="contextSource" ref="contextSource" />
</bean>
<bean id="contactDao" class="com.apps.ldap.daos.impl.Userservice">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
<bean id="myDataAccessObject" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="contactDao" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRES_NEW</prop>
</props>
</property>
</bean>
JARs used:
apache-commons-lang.jar
commons-logging-1.1.1.jar
ibatis-2.3.0.677.jar
jt400.jar
ldapbp-1.0.jar
org.springframework.aop-3.0.5.RELEASE.jar
org.springframework.asm-3.0.5.RELEASE.jar
org.springframework.beans-3.0.5.RELEASE.jar
org.springframework.context-3.0.5.RELEASE.jar
org.springframework.expression-3.0.5.RELEASE.jar
org.springframework.jdbc-3.0.5.RELEASE.jar
org.springframework.oxm-3.0.5.RELEASE.jar
org.springframework.test-3.0.5.RELEASE.jar
org.springframework.transaction-3.0.5.RELEASE.jar
org.springframework.web-3.0.5.RELEASE.jar
spring-core-3.0.4.RELEASE.jar
spring-ldap-1.1.2.jar
spring-ldap-core-1.3.2.RELEASE.jar
spring.jar
SpringUtils-0.2.jar

Spring PropertyPlaceholderConfigurer not passing property values to bean

I have a very simple requirement which has turned complicated and I have spent a day on it without any luck. I have a properties file called jdbc.properties which has the DB connection details. I need to create a datasource connection with the values from the property file. The property value is not being passed right now, leading to DB connectivity error messages. If I hardcode the property values in the bean, it works. My spring config file myBatis.DataSource.config.xml looks like this.
<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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">
<bean id="newProperty"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" lazy-
init="true">
<property name="locations" value="jdbc.properties.${env}"/>
</bean>
<bean id="newDataSource" class="org.apache.commons.dbcp.BasicDataSource" depends-
on="newProperty" destroy-method="close">
<property name="username" value="${DBUSER}" />
<property name="password" value="${DBPASSWORD}" />
<property name="url" value="${DBURL}" />
<property name="driverClassName" value="${DRIVER}" />
<property name="poolPreparedStatements" value="false" />
<property name="defaultAutoCommit" value="false" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
<property name="defaultTransactionIsolation" value="2" />
<property name="timeBetweenEvictionRunsMillis" value="10000" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation"
value="com/automation/config/oneValidation-config.xml" />
<property name="dataSource" ref="newDataSource" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<property name="basePackage" value="com.automation.config" />
</bean>
</beans>
The value for ${env} is passed as a system property to the class. The code for the class is as below:
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MybatisTest {
public static void main(String[] args) {
MybatisTest mybatisTest = new MybatisTest();
mybatisTest.testSelectQuery();
}
public void testSelectQuery(){
String resource = "oneValidation-config.xml";
SqlSession session = null;
try {
ApplicationContext context = new ClassPathXmlApplicationContext("myBatis.DataSource.config.xml");
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)context.getBean("sqlSessionFactory");
session = sqlSessionFactory.openSession(ExecutorType.BATCH);
System.out.println("Test" +
session.selectOne("com.automation.config.PostingMapper.
countByExample",null));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(session != null)
session.close();
}
}
}
The error I am getting is as shown below and is sue to the fact that the ${DBUSER}, ${DBPASSWORD} fields are not being retrieved from the property file jdbc.properties:
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause:
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC
Connection; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot
create PoolableConnectionFactory (JZ00L: Login failed. Examine the SQLWarnings chained
to this exception for the reason(s).)
I ran accross this as well. In the mybatis documentation here I found why this happens.
From the source: "NOTE sqlSessionFactoryBean and sqlSessionTemplateBean properties were the only option available up to MyBatis-Spring 1.0.2 but given that the MapperScannerConfigurer runs earlier in the startup process that PropertyPlaceholderConfigurer there were frequent errors. For that purpose that properties have been deprecated and the new properties sqlSessionFactoryBeanName and sqlSessionTemplateBeanName are recommended."
Try changing your MapperScannerConfigurer bean from
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<property name="basePackage" value="com.automation.config" />
</bean>
to
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<property name="basePackage" value="com.automation.config" />
</bean>
Try this:
<property name="locations" value="classpath:/yourFolderName/jdbc.properties"/>

Spring Transaction Manager: Rollback doesnt work

I wish to execute few insert queries within a transaction block where if there is any error all the inserts will be rolled back.
I am using MySQL database and Spring TransactionManager for this.
Also the table type is InnoDB
I have done my configuration by following the steps mentioned here.
Following is my code (for now only one query)
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = null;
status = transactionManager.getTransaction(def);
jdbcTemplate.execute(sqlInsertQuery);
transactionManager.rollback(status);
Spring config xml:
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
Datasource config:
<bean id="dataSource" class="org.apache.commons.dbcp.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="initialSize" value="${jdbc.initialSize}" />
<property name="maxActive" value="${jdbc.maxActive}" />
<property name="minIdle" value="${jdbc.minIdle}" />
<property name="maxIdle" value="${jdbc.maxIdle}" />
<property name="testOnBorrow" value="${jdbc.testOnBorrow}" />
<property name="testWhileIdle" value="${jdbc.testWhileIdle}" />
<property name="testOnReturn" value="${jdbc.testOnReturn}" />
<property name="validationQuery" value="${jdbc.validationQuery}" />
<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}" />
<!--<property name="removeAbandoned" value="true"/> <property name="removeAbandonedTimeout"
value="10"/> <property name="logAbandoned" value="false"/> -->
<property name="numTestsPerEvictionRun" value="${jdbc.numTestsPerEvictionRun}" />
</bean>
This code works perfectly fine and the record gets inserted.
But the rollback doesnt work! It executes the rollback statement without any error but to no effect.
Can anyone guide me where am I going wrong?
It appears that the issues is your datasource is not set to have autocommit off.
<property name="defaultAutoCommit" value="false"/>
Give that a try. I have never used the TransactionManager outside of a proxy so I am not sure if there any other gotchas using it directly like this, but I would recommend you look at either AOP transactions or the convience AOP proxy annotation #Transactional just because it is more common.
EDIT:
I was finally able to resolve this by doing the following:
dmlDataSource.setDefaultAutoCommit(false); //set autocommit to false explicitly.
Exception ex = (Exception)transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus ts) {
try {
dmlJdbcTemplate.execute(sqlInsertQuery);
ts.setRollbackOnly();
dmlDataSource.setDefaultAutoCommit(true); // set autocommit back to true
return null;
} catch (Exception e) {
ts.setRollbackOnly();
LOGGER.error(e);
dmlDataSource.setDefaultAutoCommit(true); // set autocommit back to true
return e;
}
}
});
I am not using the transaction manager now. Using the trasactionTemplate and doing the following:
Exception ex = (Exception)transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus ts) {
try {
dmlJdbcTemplate.execute(sqlInsertQuery);
ts.setRollbackOnly();
return null;
} catch (Exception e) {
ts.setRollbackOnly();
LOGGER.error(e);
return e;
}
}
});
after using #Moles-JWS's answer I am now able to rollback successfully. But I want to handle this only in this method and not change the global configuration of the datasource.
Can I do it here programmatically?

Resources