Apply Transaction Management Spring - spring

I have a j2ee application running on spring framework. I am trying to apply transaction management using aop but apparently it won't work. I am trying to apply transaction to a function from a class named RegisterBLogic with function name execute(ParamObject obj). My function inserts into a database. I also put a throw ne Exception my function to force the throwing of exception.
Inside userManagerContext:
<bean id="RegisterBLogic"
scope="singleton"
class="jp.co.anicom.fw.web.usermanager.blogic.RegisterBLogic">
<property name="queryDAO"
ref="queryDAO" /> <property
name="updateDAO" ref="updateDAO" />
</bean>
Inside ApplicationContext
<bean id="TerasolunaDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="PrototypeDataSource" />
</bean>
<tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"
rollback-for="java.lang.Exception" />
<tx:method name="execute*" propagation="REQUIRED"
rollback-for="java.lang.Exception" />
<tx:method name="*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- AOPの設定 -->
<aop:config>
<aop:pointcut id="blogicBeans" expression="bean(*BLogic)" />
<aop:pointcut id="serviceBeans" expression="bean(*Service)" />
<aop:advisor pointcut-ref="blogicBeans" advice-ref="transactionInterceptor" />
<aop:advisor pointcut-ref="serviceBeans" advice-ref="transactionInterceptor" />
</aop:config>
Yeah these beans already exist. I have this bean declaration under userManagerCOntext.xml. This xml is loaded in the struts config through
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/userManager/userManagerContext.xml"/>
</plug-in>
I found the problem. Currently i am using a data source from a JNDI.
class="org.springframework.jndi.JndiObjectFactoryBean">
i changed it to normal data source with property defaultAutoCommit set to false
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="oracle.jdbc.OracleDriver" />
<property name="url"
value="jdbc:oracle:thin:#192.168.178.82:1521:anicom" />
<property name="username" value="jay" />
<property name="password" value="jay" />
<property name="initialSize" value="5" />
<property name="maxActive" value="10" />
<property name="defaultAutoCommit" value="false" />
</bean>
How do I use JNDI data source but be able to set a property somewhat similar to defaultAutoCommit to false. I am using Oracle weblogic server and my data source is stored in it accessed through JNDI

First of all, this XML is malformed (should be </tx:advice>).
Are the beans you want to wrap in AOP already present when this configuration is processed?

Related

Quartz scheduler not scheduling/firing the jobs

I try to schedule a quartz scheduler with spring-4.3.27 and quartz-2.3.2 with xml based configuration, Jobs are not getting fired.
Earlier its working quartz-2.1.1 and quartz-all-2.1.1, Now I migrated to quartz-2.3.2 (Quratz-all-2.3.2 which is not available), But the jobs are not getting triggered.
my Quartz Scheduler Configuration like,
<task:annotation-driven />
<!-- enable this for websphere -->
<bean name="workManagerTaskExecutor"
class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
<property name="resourceRef" value="true" />
<property name="workManagerName" value="wm/default" />
</bean>
<bean name="quartzScheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="taskExecutor" ref="workManagerTaskExecutor" />
<property name="autoStartup" value="true" />
<property name="nonTransactionalDataSource" ref="dataSource" />
<!-- <property name="transactionManager" ref="transactionManager" /> -->
<property name="quartzProperties">
<util:properties location="classpath:/quartz.properties" />
</property>
<property name="waitForJobsToCompleteOnShutdown" value="true" />
<property name="jobDetails">
<list>
<ref bean="Job1" />
</list>
</property>
<property name="triggers">
<list>
<ref bean="jobTrigger" />
</list>
</property>
<property name="schedulerContextAsMap">
<map>
<entry key="messageExchangeLogDAO" value-ref="MessageExchangeLogDAO" />
<entry key="outboundMessageSender" value-ref="outboundMessageSender" />
<entry key="marshaller" value-ref="marshaller" />
<entry key="reportService" value-ref="reportService" />
<entry key="userDao" value-ref="UserDAO" />
<entry key="jobService" value-ref="jobService" />
<entry key="purchaseOrderDAO" value-ref="PurchaseOrderDAO" />
<entry key="dbConfig" value-ref="databaseConfiguration" />
<entry key="purchaseOrderService" value-ref="purchaseOrderService" />
<entry key="userRoleDAO" value-ref="userRoleDAO" />
<entry key="mailService" value-ref="mailService" />
<entry key="buyerNotificationService" value-ref="buyerNotificationService" />
<entry key="supplierNotificationService" value-ref="supplierNotificationService" />
<entry key="adminNotificationService" value-ref="adminNotificationService" />
<entry key="messageService" value-ref="messageService" />
<entry key="messageProcessor" value-ref="messageProcessor" />
<entry key="em" value-ref="entityManagerFactory"/>
<entry key="invoiceService" value-ref="invoiceService" />
<entry key="approvedInvoiceDAO" value-ref="ApprovedInvoiceDAO" />
</map>
</property>
</bean>
<bean
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="jobTrigger"
class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="job1" />
<property name="startDelay" value="0" />
<property name="repeatInterval" value="300000" />
</bean>
<bean name="job1"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.jobs.scheduleJob" />
</bean>
<aop:config>
<aop:pointcut id="quartzSchedulerPointcut"
expression="execution(* org.quartz.Scheduler.*(..))" />
<aop:advisor advice-ref="quartzSchedulerAdvice"
pointcut-ref="quartzSchedulerPointcut" />
</aop:config>
<tx:advice id="quartzSchedulerAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true" propagation="SUPPORTS" />
<tx:method name="set*" read-only="true" propagation="SUPPORTS" />
<tx:method name="is*" read-only="true" propagation="SUPPORTS" />
<tx:method name="insert*" read-only="false" propagation="REQUIRED" />
<tx:method name="update*" read-only="false" propagation="REQUIRED" />
<tx:method name="delete*" read-only="false" propagation="REQUIRED" />
<tx:method name="schedule*" read-only="false" propagation="REQUIRED" />
<tx:method name="pause*" read-only="false" propagation="REQUIRED" />
<tx:method name="resume*" read-only="false" propagation="REQUIRED" />
<tx:method name="run*" read-only="false" propagation="REQUIRED" />
<tx:method name="update*" read-only="false" propagation="REQUIRED" />
<tx:method name="delete*" read-only="false" propagation="REQUIRED" />
<tx:method name="toggle*" read-only="false" propagation="REQUIRED" />
<tx:method name="clone*" read-only="false" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
Quartz.properies:
org.quartz.scheduler.instanceName = TSPScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.class = org.springframework.scheduling.quartz.LocalDataSourceJobStore
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.clusterCheckinInterval=1000
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.misfireThreshold = 10000
org.quartz.jobStore.selectWithLockSQL = SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE
org.quartz.jobStore.dontSetAutoCommitFalse = false
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 15
org.quartz.threadPool.threadPriority = 15
org.quartz.jobStore.isClustered = true
Logs:
org.springframework.scheduling.quartz.SchedulerFactoryBean startScheduler Starting Quartz Scheduler now
org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor finishRegistration **No TaskScheduler/ScheduledExecutorService bean found for scheduled processing**
After that No error and nothing is getting printed in the Logs, at the same time jobs also not getting fired.
In the QUARTZ_TRIGGERS table next_fire_time alone getting updated based fire interval.
Note: The same configuration working fine with quartz-2.1.1 and quartz-all-2.1.1, Not working with quartz-2.3.2
anyone guide me where I did mistake? what I need to do here to resolve this scheduling issue?
sched_time column is missing in qrtz_fired_triggers table. After adding that column its started firing.
There are lots of differences between the tables from 1.x to 2.x. We recently migrated from 1.x and created all tables before deploying the application.

How to join Spring JMS transactions from two different connection factories?

I am using different connection factories for sending and receiving messages, having trouble with partial commit issues incase of delivey failures. jms:message-driven-channel-adapter uses the receiveConnectionFactory ro receive the messages from the queue. jms:outbound-channel-adapter uses the deliverConnectionFactory to send the messages multiple to downstream queues. We have only one JmsTransactionManager which uses the receiveConnectionFactory and the jms:outbound-channel-adapter configured with session-transacted="true".
<beans>
<bean id="transactionManager"
class="org.springframework.jms.connection.JmsTransactionManager">
<property name="connectionFactory" ref="receiveConnectionFactory" />
</bean>
<bean id="receiveConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory">
<bean class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName" value="${mq.host}" />
<property name="channel" value="${mq.channel}" />
<property name="port" value="${mq.port}" />
</bean>
</property>
<property name="sessionCacheSize" value="${receive.factory.cachesize}" />
<property name="cacheProducers" value="${receive.cache.producers.enabled}" />
<property name="cacheConsumers" value="${receive.cache.consumers.enabled}" />
</bean>
<bean id="deliverConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory">
<bean class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName" value="${mq.host}" />
<property name="channel" value="${mq.channel}" />
<property name="port" value="${mq.port}" />
</bean>
</property>
<property name="sessionCacheSize" value="${send.factory.cachesize}" />
<property name="cacheProducers" value="${send.cache.producers.enabled}" />
<property name="cacheConsumers" value="${send.cache.consumers.enabled}" />
</bean>
<tx:advice id="txAdviceNew" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="send" propagation="REQUIRES_NEW" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="txAdviceNew" pointcut="bean(inputChannel)" />
<aop:advisor advice-ref="txAdviceNew" pointcut="bean(errorChannel)" />
</aop:config>
<jms:message-driven-channel-adapter
id="mdchanneladapter" channel="inputChannel" task-executor="myTaskExecutor"
connection-factory="receiveConnectionFactory" destination="inputQueue"
error-channel="errorChannel" concurrent-consumers="${num.consumers}"
max-concurrent-consumers="${max.num.consumers}" max-messages-per-task="${max.messagesPerTask}"
transaction-manager="transactionManager" />
<jms:outbound-channel-adapter
connection-factory="deliverConnectionFactory" session-transacted="true"
destination-expression="headers.get('Deliver')" explicit-qos-enabled="true" />
</beans>
When there is MQ exception on any one destination, the partial commit occurs and then the failure queue commit happens. I am looking to see if I am missing some configuration to join the transactions so that the partial commit never happens.
I tried with only one connection factory for both send and receive (receiveConnectionFactory) and the parital commit is not happening, everything works as expected.
I tried with only one connection factory for both send and receive (receiveConnectionFactory) and the parital commit is not happening, everything works as expected.
That's the right way to go in your case.
I see that your two ConnectionFactories are only different by their objects. Everything rest looks like the same target MQ server.
If you definitely can't live with only one ConnectionFactory, you should consider to use JtaTransactionManager or configure org.springframework.data.transaction.ChainedTransactionManager for two JmsTransactionManagers - one per connection factory.
See Dave Syer's article on the matter: https://www.javaworld.com/article/2077963/open-source-tools/distributed-transactions-in-spring--with-and-without-xa.html

SQLRecoverableException: Error de E/S connection abort: recv failed

I have a problem with the connection to the database, after a period of inactivity in the application, I return to enter and send me the following error
01-08-2014 04:45:33 PM org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: Servlet.service() para servlet springapp lanzó excepción
org.springframework.dao.DataAccessResourceFailureException:
### Error querying database. Cause: java.sql.SQLRecoverableException: Error de E/S: Software caused connection abort: recv failed
and this is my oracle data source
<!-- Load properties with PlaceHolder -->
<context:property-placeholder location="WEB-INF/properties/*.properties" />
<bean id="dataSource" 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}" />
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<aop:config>
<!-- aop:advisor pointcut="execution(* *..Service.*(..))" advice-ref="txAdvice"/ -->
<aop:pointcut id="fooServiceOperation" expression="execution(* cl.bbr.proceso.maestro.proceso.ProcesoMaestro.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- all methods starting with 'get','is','select' are read-only -->
<tx:method name="get*" read-only="true"/>
<tx:method name="is*" read-only="true"/>
<tx:method name="select*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<tx:advice id="noTxAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRES_NEW" />
</tx:attributes>
</tx:advice>
EDIT 05/08/2014
DATABASE : ORACLE 11G
SPRING VERSION : 3.0
TOMCAT 6.0
hopefully you can help me thanks.
Adding this lines to dataSource bean solved the problem:
<property name="validationQuery" value="SELECT 1 from dual" />
<property name="testOnBorrow" value="true" />
About validation query you can read in the answer for this question: What is a validationQuery with respect to databases and JNDI?
"testOnBorrow" means that before every query execution validationQuery will be executed.

Choose between muliple transaction managers at runtime

I have 2 clients using same Spring based REST Application deployed in tomcat. Depending on client I need to choose between data sources and transaction manager. How do I choose at runtime, which transaction manager to use?
<bean id="First_dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="url" value="${First_jdbc.url}" />
<property name="driverClassName" value="${First_jdbc.driverClassName}" />
<property name="username" value="${First_jdbc.username}" />
<property name="password" value="${First_jdbc.password}" />
<property name="removeAbandoned" value="true" />
<property name="initialSize" value="20" />
<property name="maxActive" value="30" />
<!-- <property name="defaultAutoCommit" value="false" /> -->
</bean>
<bean id="Second_dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="url" value="${Second_jdbc.url}" />
<property name="driverClassName" value="${Second_jdbc.driverClassName}" />
<property name="username" value="${Second_jdbc.username}" />
<property name="password" value="${Second_jdbc.password}" />
<property name="removeAbandoned" value="true" />
<property name="initialSize" value="20" />
<property name="maxActive" value="30" />
<!-- <property name="defaultAutoCommit" value="false" /> -->
</bean>
<bean id="First_TransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
scope="singleton">
<property name="dataSource" ref="First_dataSource" />
<qualifier value="SC_TM"></qualifier>
</bean>
<bean id="Second_TransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
scope="singleton">
<property name="dataSource" ref="Second_dataSource" />
<qualifier value="Second_TM"></qualifier>
</bean>
In code how do choose #Transactional("????") at run time.
If it is not possible with org.springframework.jdbc.datasource.DataSourceTransactionManager is there any other way of doing it?
Using #Transactional, you can specify the transaction manager like this:
#Transactional("First_TransactionManager")
or
#Transactional("Second_TransactionManager")
depending on which one you want to use. Make sure to use inside the transactional method the correct Entity Manager / session factory. Those you also have to specify which one you want to inject with #PersistenceContext("nameOfPersistenceUnit").
I do not know why you want to change between the 2 transaction manager may be you need to check Transaction manager chain solution, but in case you need this you can add your #transactional on Repo methods and do 2 Repos and manage it from the service layer as switch, otherwise I'm believing that there is solution could be done using AOP but it will need more time to think about it.
Problem is solved through AOP.
Define multiple data sources and corresponding Transacation Manager (as I have shown in my
base question)
First_dataSource mapped with First_TransactionManager and Second_dataSource mapped with Second_TransactionManager
Select which data source to use programatically depending on your business rules. In my case it was orgId
public class DataSourceProvider {
#Autowired
DataSource First_dataSource;
#Autowired
DataSource Second_dataSource;
public DataSource getDataSource(int orgId) {
if (orgId == Constants.BUSINESS_PARTY_1)
return Second_dataSource;
else
return First_dataSource;
}
public DataSource getFirst_dataSource() {
return First_dataSource;
}
public void setFirst_dataSource(DataSource First_dataSource) {
First_dataSource = First_dataSource;
}
public DataSource getSecond_dataSource() {
return Second_dataSource;
}
public void setSecond_dataSource(DataSource Second_dataSource) {
Second_dataSource = Second_dataSource;
}
}
AOP Configuration:
<tx:advice id="First_txAdvice" transaction-manager="First_TransactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="First_daoimplOperation"
expression="execution(* in.company.common.service.CommonServiceImpl.*(..))" />
<aop:advisor advice-ref="First_txAdvice" pointcut-ref="First_daoimplOperation" />
</aop:config>
<tx:advice id="Second_txAdvice" transaction-manager="Second_TransactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="Second_daoimplOperation"
expression="execution(* in.company.common.service.CommonServiceImpl.*(..))" />
<aop:advisor advice-ref="Second_txAdvice" pointcut-ref="Second_daoimplOperation" />
</aop:config>
all database related services should be in matching pointcut like in this case it is: in.company.common.service.CommonServiceImpl.*(..))
Consider using the Spring provided AbstractRoutingDataSource instead of going down the path of choosing between multiple transaction managers. It will be a much cleaner solution.
See my answer to a similar question here :
https://stackoverflow.com/a/44167079/2200690

Why does AOP managed transactions not work in my unit tests?

I've configured Spring solely based on XML. Transactions are managed by Hibernate, and I'm using AOP to manage transaction boundaries.
However, when running unit tests, why is it that my AOP configuration not kicks in? I need to add annotations such as #Transactional to the test method to make sure that database operations gets wrapped in transactions, even though I've configured AOP to wrap calls to service methods in transactions.
Why doesn't my AOP configuration apply to tests also?
applicationcontext.xml
<aop:aspectj-autoproxy/>
<!-- Data Source -->
<bean id="companyDomainDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.master.url}" />
<property name="user" value="${jdbc.master.username}" />
<property name="password" value="${jdbc.master.password}" />
<property name="acquireIncrement" value="1" />
<property name="minPoolSize" value="2" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="4" />
</bean>
<!-- Session Factory -->
<bean id="companyDomainSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="companyDomainDataSource"/>
<property name="mappingResources">
<list>
<value>/com/company/pas/entity/mapping/partner.hbm.xml</value>
</list>
</property>
</bean>
<!-- Transaction Manager -->
<bean id="companyDomainTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="companyDomainSessionFactory"/>
</bean>
<!-- Transaction Advice -->
<tx:advice id="companyDomainTransactionAdvise" transaction-manager="companyDomainTransactionManager">
<tx:attributes>
<!--<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceMethods" expression="within(com.company.pas.dao.*)"/>
<aop:advisor advice-ref="companyDomainTransactionAdvise" pointcut-ref="serviceMethods"/>
</aop:config>
unit test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/applicationContext.xml"})
#TransactionConfiguration(transactionManager="companyDomainTransactionManager", defaultRollback=true)
public class PartnerCreateTest extends AbstractActionTest {
#Autowired #Qualifier("createPartnerAction") AbstractAction action;
#Test
#Transactional
public void testExecute() throws Exception {
// Create partner.
Representation rep = mock(Representation.class);
Request req = mock(Request.class);
Response resp = mock(Response.class);
when(rep.getText()).thenReturn(getContentsOf("com/company/pas/entity/xml/partner-create.xml"));
when(req.getEntity()).thenReturn(rep);
AbstractRequestModel crm = action.getRequestModelParser().parse(req, resp);
action.execute(crm);
}
}
When you add #Transactional to a test method you get a rollback by default. When you don't you should expect transactions to commit (they don't know they are in a test).

Resources