Spring Transaction Manager: Rollback doesnt work - spring

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?

Related

Oracle AQ JMS with XA transaction throwing NullPointException while fetching connection

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);
}
}

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.

Spring 4 + Hibernate 5.1 Transaction auto committed after call another DAO query

I have a problem with transaction auto committed after call another dao native query.
Both service and dao signed as #Transactional.
What am I doing wrong here?
Spring 4.2.x
Hibernate 5.1.0
Atomikos 3.9.3
This is my setup:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="jtaPlatformAdapter" class="com.xxx.JtaPlatformAdapter">
<property name="jtaTransactionManager" ref="transactionManager" />
</bean>
<bean class="com.atomikos.icatch.jta.UserTransactionManager" destroy-method="close" id="atomikosTransactionManager" init-method="init">
<property name="forceShutdown" value="true" />
<property name="startupTransactionService" value="true" />
</bean>
<bean class="com.atomikos.icatch.jta.UserTransactionImp" id="atomikosUserTransaction" />
<bean class="org.springframework.transaction.jta.JtaTransactionManager" id="transactionManager">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
</bean>
<bean id="datasouce" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
...
</bean>
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" id="JPAVendorAdapter">
...
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="emf" depends-on="transactionManager,jtaPlatformAdapter">
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
<property name="packagesToScan" value="com.xxx.server"/>
<property name="dataSource" ref="datasouce" />
<property name="persistenceUnitName" value="pun" />
<property name="jpaVendorAdapter" ref="JPAVendorAdapter" />
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.connection.release_mode" value="on_close" />
<entry key="hibernate.transaction.jta.platform" value="com.xxx.server.JtaPlatformAdapter" />
</map>
</property>
</bean>
persistence.xml
<persistence-unit name="pun" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
service
#Transactional
#Scope("prototype")
public synchronized void save(EntityObj model) throws Exception {
model.setX(30);
model.setY(40);
EntityObj oldModel = entityObjDAO.findById(model.getId());
// after call findById, the model had been commit to DB
...
...
...
entityObjDAO.store(model); // this will call entityManager.merge(model)
entityObjDAO.flush();
}
DAO
#Transactional
public EntityObj findById(String id) {
EntityObj model = null;
String sql = "select id,x,y from EntityObj where id = :id"; // this is a native sql query
Query query = this.entityManager.createNativeQuery(sql);
query.setParameter("id", id);
Object[] rs = (Object[]) query.getSingleResult();
if (rs != null) {
model = new EntityObj();
model.setId(id);
model.setX(rs[1] == null ? null : (Integer) rs[1]);
model.setY(rs[2] == null ? null : (Integer) rs[2]);
}
return model;
}
thanks!
If you are using #Transactional in your code, Spring creates a proxy object for your Dao object (wrapper).
So it looks like this if your application is running:
public EntityObj proxyMethodForFindById(String id) {
try {
// 1. start transaction
startTransaction();
// 2. execute your code
return yourDaoObject.findById(id);
} finally { // [!] PSEUDO CODE: NO EXCEPTION HANDLING
// commit transaction
commitTransaction();
}
}
So what happens in your code?
Your save method is marked also as #Transactional. So if you are changing your object by setting:
model.setX(30);
model.setY(40);
Spring creates two proxies. One for Service and one four your Dao. On the End of the findById-Transaction this changes will be commited. Nested transactions is the keyword.
You should remove #Transaction in your findById-Method or better in the whole Dao object. Service should be transactional, not Dao-layer.

Spring JpaTransactionManager not saving Activiti entities to DB

Nothing about Activiti is being saved to database. Application entities ARE being saved to database. Below, in order are, the spring file, persitence.xml file and the test case.
Using SQL Server profiler, I see a separate database transaction being started for the database interaction caused by Activiti and further I see that separate transaction being rolled back instead of being committed. Other application db interaction is happening on another transaction and this particular transaction is being committed.
I thought, given my configurations, Activiti database interaction would happen on the same transaction as the rest of the application. I have gone through my configuration files and code numerous times and do not see anything wrong therein. Any ideas why a separate transaction is being started for the Activiti db interactions?
Of course the previous item is the critical question. However, it would also be interesting to know why is that separate transaction being rolled back?
Spring file :
<context:annotation-config/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="ActivitiTrialDataSource" class="org.apache.commons.dbcp.BasicDataSource" >
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver" />
<property name="url" value="jdbc:jtds:sqlserver://localhost:1433/ActivitiTrial" />
<property name="username" value="ActivitiTrial" />
<property name="password" value="ActivitiTrial" />
<property name="defaultAutoCommit" value="false" />
<property name="initialSize" value="5" />
</bean>
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="ActivitiTrialDataSource" />
<property name="persistenceUnitName" value="ActivitiTrial"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- Activiti -->
<bean id="activitiDataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<property name="targetDataSource" ref="ActivitiTrialDataSource" />
</bean>
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="databaseType" value="mssql" />
<property name="dataSource" ref="activitiDataSource" />
<property name="transactionsExternallyManaged" value="true" />
<property name="transactionManager" ref="transactionManager" />
<property name="databaseSchemaUpdate" value="false" />
<property name="history" value="audit" />
<property name="jobExecutorActivate" value="false" />
</bean>
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
<bean id="activitiRepositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
<bean id="activitiRuntimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
<bean id="activitiTaskService" factory-bean="processEngine" factory-method="getTaskService" />
<bean id="activitiHistoryService" factory-bean="processEngine" factory-method="getHistoryService" />
<bean id="activitiManagementService" factory-bean="processEngine" factory-method="getManagementService" />
persitence.xml file:
<persistence-unit name="ActivitiTrial">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.archive.autodetection" value="hbm,class"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
<property name="hibernate.hbm2ddl.auto" value="none"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.ejb.metamodel.generation" value="disabled"/>
</properties>
</persistence-unit>
Test case:
#RunWith(SpringJUnit4ClassRunner.class)
#TransactionConfiguration(defaultRollback=false)
#ContextConfiguration({"classpath:/springApplicationContext.xml"})
public class TrialTest {
#Autowired
RepositoryService activitiRepositoryService;
#Autowired
RuntimeService activitiRuntimeService;
#Autowired
TaskService activitiTaskService;
#PersistenceContext(unitName="ActivitiTrial")
EntityManager entityManager;
#Test
#Transactional
public void trialTest() throws Exception {
long entryMilliseconds = new Date().getTime();
activitiRepositoryService.createDeployment().addClasspathResource("process-definitions/neville.bpmn20.xml").deploy();
ApplicationEntity applicationEntity1 = new ApplicationEntity();
applicationEntity1.name = "App entity 1";
applicationEntity1.createDate = new Date();
Session hibernateSessionBeforeActiviti = ((Session) entityManager.getDelegate());
entityManager.persist(applicationEntity1);
entityManager.flush();
Map<String, Object> processVariables = new HashMap<String, Object>();
processVariables.put("ApplicationEntityID", applicationEntity1.id);
ProcessInstance processInstance = activitiRuntimeService.startProcessInstanceByKey("neville", processVariables);
String processInstanceId = processInstance.getId();
Task userTask = activitiTaskService.createTaskQuery().processInstanceId(processInstanceId).list().get(0);
ApplicationEntity applicationEntity2 = new ApplicationEntity();
applicationEntity2.name = "App entity 2";
applicationEntity2.createDate = new Date();
Session hibernateSessionAfterActiviti = ((Session) entityManager.getDelegate());
entityManager.persist(applicationEntity2);
entityManager.flush();
System.out.println("Leaving trialTest() in : " + (new Date().getTime() - entryMilliseconds) + " milliseconds.");
}
}
I've solved this problem by resolving conflict between MyBatis (JDBC) and Hibernate (JPA):
You should add jpaVendorAdapter property to entityManagerFactory bean:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="ActivitiTrialDataSource" />
<property name="persistenceUnitName" value="ActivitiTrial"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
For more details see answer of this question.
I've already waste a lot of time trying to pass common transaction manager to Spring and Activiti - and no result. No mean of full answer to your question, but I hope it will save you some time
Activiti forum:
http://forums.activiti.org/content/activiti-doesnt-submit-rollback
http://forums.activiti.org/content/activitispringhibernate-common-transaction-manager
Demo:
These repos illustrate that Activiti don't accept jpa/hibernate transactions:
https://github.com/JOLO-/activiti-jpa-spring-transaction-demo.git
https://github.com/JOLO-/activiti-hibernate-spring-transaction-demo.git
You also can see demo https://github.com/Activiti/Activiti (Activiti + Spring + Bitronix) it may help (I have no time to check it yet).
P.S.
As an alternative to common transaction I see compensation events.

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"/>

Resources