I have a simple standalone application to test transaction management with Spring.
Have Oracle Express Edition.
Run the following to enable XA
grant select on sys.dba_pending_transactions to user_test;
grant select on sys.pending_trans$ to user_test;
grant select on sys.dba_2pc_pending to user_test;
grant execute on sys.dbms_system to user_test;
My Java code is pretty much as follow:
public class DbUpdater
{
private static final ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"spring_transactions.xml"});
private static Logger log = LoggerFactory.getLogger(DbUpdater.class);
#Transactional(propagation=Propagation.REQUIRED, readOnly=false)
public void updateData() {
IMasterDAO ds1 = context.getBean("masterDao", IMasterDAO.class);
log.info("Insert using ds1");
ds1.insert("insert into users values(?,?)", "user1", "John Hamilton");
log.info("Insert using ds1 finished successfully");
throw new RuntimeException("A runtime exception");
}
}
So all the idea is too see transaction rolling back.
I run with several configuration examples and record is committed all the time.
No rollback is performed. No errors nothing, only expected
Exception in thread "main" java.lang.RuntimeException: A runtime exception
at com.test.spring.transation.DbUpdater.updateData(DbUpdater.java:22)
My last config is this:
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="bitronixTransactionManager" />
<property name="userTransaction" ref="bitronixTransactionManager" />
</bean>
<bean id="btmConfig" factory-method="getConfiguration"
class="bitronix.tm.TransactionManagerServices">
<property name="serverId" value="spring-btm" />
</bean>
<bean id="bitronixTransactionManager" factory-method="getTransactionManager"
class="bitronix.tm.TransactionManagerServices"
depends-on="btmConfig,dataSource"
destroy-method="shutdown" />
<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource"
init-method="init" destroy-method="close">
<property name="className" value="oracle.jdbc.xa.client.OracleXADataSource"/>
<property name="uniqueName" value="myOracleDataSource"/>
<property name="minPoolSize" value="0"/>
<property name="maxPoolSize" value="5"/>
<property name="allowLocalTransactions" value="true"/>
<property name="testQuery" value="select sysdate from dual"/>
<property name="driverProperties">
<props>
<prop key="user">${jdbc.username}</prop>
<prop key="password">${jdbc.password}</prop>
<prop key="URL">${jdbc.url}</prop>
</props>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="masterDao" class="com.test.spring.transation.MasterDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
</beans>
The JDBC template being instantiated via supplied data source, seems to work with its own transaction [there by the automatic begin and commit transaction]. The exception is thrown after that which operates in seperate commit/rollback cycle and hence you see that the writes persisted. To verify it, you can move the code to throw exception in MasterDAO class and examine rollback.
Related
My Requirement is I need to have two datasource connected to Spring Batch Application.
1) One for Spring Batch Jobs and Executions storing
2) One for Business Data Stroing, Processing and Retreiving.
I know that there are lot of solutions for achieving this. But I have achieved by setting the second datasource as primary. The problem is the second datasource is not coming under transaction scope instead it is committing for each sql statement executing expecially through jdbctemplate.
As I can't able to edit my question. I am writing another Post in detail
My Requirement is I need to have two datasource connected to Spring Batch Application.
1) One for Spring Batch Jobs and Executions storing
2) One for Business Data Stroing, Processing and Retreiving.
In env-context.xml I have following configuration
<!-- Enable annotations-->
<context:annotation-config/>
<bean primary="true" id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/DB2XADS"/>
</bean>
<!-- Creating TransactionManager Bean, since JDBC we are creating of type
DataSourceTransactionManager -->
<bean id="transactionManager" primary="true"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- jdbcTemplate uses dataSource -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="batchTransactionManager"
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
In override-context.xml I have the following code
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- jdbcTemplate uses dataSource -->
<bean id="batchDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/MySqlDS"/>
</bean>
<bean class="com.honda.pddabulk.utility.MyBatchConfigurer">
<property name="dataSource" ref="batchDataSource" />
</bean>
<!-- Use this to set additional properties on beans at run time -->
<bean id="placeholderProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/org/springframework/batch/admin/bootstrap/batch.properties
</value>
<value>classpath:/batch/batch-mysql.properties</value>
<value>classpath:log4j.properties</value>
</list>
</property>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="ignoreResourceNotFound" value="true"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="order" value="1"/>
</bean>
<!-- Overrider job repository -->
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="databaseType" value="mysql"/>
<property name="dataSource" ref="batchDataSource"/>
<property name="tablePrefix" value="${batch.table.prefix}"/>
<property name="maxVarCharLength" value="2000"/>
<property name="isolationLevelForCreate" value="ISOLATION_SERIALIZABLE"/>
<property name="transactionManager" ref="batchTransactionManager"/>
</bean>
<!-- Override job service -->
<bean id="jobService" class="org.springframework.batch.admin.service.SimpleJobServiceFactoryBean">
<property name="tablePrefix" value="${batch.table.prefix}"/>
<property name="jobRepository" ref="jobRepository"/>
<property name="jobLauncher" ref="jobLauncher"/>
<property name="jobLocator" ref="jobRegistry"/>
<property name="dataSource" ref="batchDataSource"/>
</bean>
<!-- Override job launcher -->
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
<property name="taskExecutor" ref="jobLauncherTaskExecutor" />
</bean>
<task:executor id="jobLauncherTaskExecutor" pool-size="21" rejection-policy="ABORT" />
<!-- Override job explorer -->
<bean id="jobExplorer"
class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
<property name="tablePrefix" value="${batch.table.prefix}"/>
<property name="dataSource" ref="batchDataSource"/>
</bean>
In job-config.xml I have the following code
<context:component-scan base-package="com.honda.*">
<context:exclude-filter type="regex"
expression="com.honda.pddabulk.utility.MyBatch*" />
</context:component-scan>
I have the custom Batch configurer set. Now the problem is when I try to execute queries with jdbctemplate for update and insert it is not under transaction which means #Transactional is not working.
Rather commit is happening for each method call. The example is
#Transactional
public void checkInsertion() throws Exception{
try{
jdbcTemplate.update("INSERT INTO TABLE_NAME(COLUMN1, COLUMN2) VALUES( 'A','AF' );
throw new PddaException("custom error");
}catch(Exception ex){
int count=jdbcTemplate.update("ROLLBACK");
log.info("DATA HAS BEEN ROLLBACKED SUCCESSFULLY... "+count);
throw ex;
}
}
In the above code I am trying to insert data and immediately I am also throwing a exception which means the insert should happen but commit will not. So we will not be able to see any data but unfortunately the commit is happening. Please some one help
this is exception i am getting while executing spring application.can anyone help me to resolve this problem.
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: drop table if exists postgres.student007 cascade
Hibernate: create table postgres.student007 (id int4 not null,address varchar(255), email varchar(255), name varchar(255), primary key (id) Exception in thread "main" org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
at org.springframework.orm.hibernate4.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1135)
at org.springframework.orm.hibernate4.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:620)
at org.springframework.orm.hibernate4.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:617)
at org.springframework.orm.hibernate4.HibernateTemplate.doExecute(HibernateTemplate.java:340)
at org.springframework.orm.hibernate4.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:308)
at org.springframework.orm.hibernate4.HibernateTemplate.save(HibernateTemplate.java:617)
at dao.StudentDaoImplHT.save(StudentDaoImplHT.java:22)
at test.Client.main(Client.java:21)
below is my configuration config.xml file.can anyone help me to resolve this problem.
<beans>
<bean id="bds" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql://localhost:5432/postgres"/>
<property name="username" value="postgres"/>
<property name="password" value="postgres"/>
<property name="maxActive" value="15"/>
<property name="maxIdle" value="5"/>
<property name="maxWait" value="5000"/>
</bean>
<!-- <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="bds"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>model.Student</value>
</list>
</property>
</bean>
<bean id="ht" class="org.springframework.orm.hibernate4.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="dao" class="dao.StudentDaoImplHT">
<property name="ht" ref="ht"/>
</bean>
</beans>
It's the problem of spring transaction. You need to config transaction
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Then enable the annotation configure for transaction
<tx:annotation-driven />
At last, add the transaction configure in your method.
#Transactional(propagation = Propagation.REQUIRED, readOnly = false)
You problem is that you didn't use the transaction but do writing things into database. It's not allowed, you should create a transaction and make the readOnly = false. Then you can create table.
You can use jdbcTemplate.execute(sql). to create table.
I have created a oracle datasource in weblogic with the name jdbc/myDS.
Weblogic created a xml file in mydomain/config/jdbc and the configuration works from the weblogic admin console. Test connection is working. My spring context file details are:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/myDS"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<util:map>
<entry key="hibernate.hbm2ddl.auto" value="update" />
<entry key="hibernate.show_sql" value="true" />
</util:map>
</property>
</bean>
<bean id="myDAO" class ="com.example.MyDAOImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
My Java class is:
public class MyDAOImpl implements MyDAO{
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void persistPerson(Person person) {
Session session = getSessionFactory().openSession();
try {
session.beginTransaction();
session.save(person);
session.getTransaction().commit();
}catch(HibernateException he) {
he.printStackTrace();
} finally {
session.close();
}
}
}
An error occurred during activation of changes, please see the log for
details.
Message icon - Error weblogic.application.ModuleException:
Message icon - Error While trying to lookup 'jdbc.myDS' didn't find subcontext 'jdbc'. Resolved ''; remaining name 'jdbc/myDS'
The following provides a Spring XML configuration to obtain a datasource by a JNDI name and inject it into Springs AnnotationSessionFactoryBean.
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/YourJndi"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="annotatedClasses">
<list>
<value>com.java.model.Employee</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
This example has been sucessfully tested on Weblogic 10.3.4 with Oracle 11g.
I am new to mule.
I have a spring-hibernate mule setup. Suppose there are 3 webservice.Aim is to invoke all those webservice in a mule flow so that all 3 will be in a transaction. so that suppose if 3rd webservice fails then the previous 2 will be rolled back automatically.
Here is my code snippet what I tried.
my mule-flow.xml(currently I have only one webservice,kindly let me know how can I add multipe webservice call in flow?)
<spring:beans>
<spring:import resource="classpath:spring-mule.xml"/>
<spring:import resource="classpath:applicationContext-persistence.xml"/>
</spring:beans>
<flow name="addCustomer" doc:name="addCustomer">
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8081/pos/addCustomer" doc:name="HTTP" />
<cxf:simple-service serviceClass="com.proj.pos.webservice.interfac.CustomerService" doc:name="SOAP"/>
<component ><spring-object bean="customerService"/></component>
</flow>
</mule>
My spring-mule.xml
<bean id="customerService" class="com.proj.pos.webservice.implementation.CustomerServiceImpl">
<property name="cusDao" >
<ref local="customerDao"/>
</property>
</bean>
My:applicationContext-persistence.xml
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:xe" />
<property name="username" value="xyz" />
<property name="password" value="xyz" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="datasource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
<prop key="hibernate.connection.release_mode">auto</prop>
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="customerDao" class="com.proj.pos.dao.implementation.CustomerDaoImpl">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
my CustomerServiceImpl
#WebService(endpointInterface = "com.proj.pos.webservice.interfac.CustomerService",
serviceName = "CustomerService")
public class CustomerServiceImpl implements CustomerService {
#Autowired
private CustomerDao cusDao;
#Transactional //NOTE:USING THIS ANNOTATION I AM ABLE TO ACHIEVE THE BELOW METHOD //IN TRANSACTION,BUT I BELEIVE THIS FEATURE WILL NOT WORK IF WE HAVE MULTIPLE WEBSERVICE CALL
#Override
public Customer addCustomer(CustomerDto dto) {
Customer customer=new Customer(dto.getCustomerId(), dto.getFname(), dto.getLname(), dto.getAge(), dto.getDateOfBirth(), dto.getAddress());
customer.setCustomerId(cusDao.persist(customer));
return customer;
}
public CustomerDao getCusDao() {
return cusDao;
}
public void setCusDao(CustomerDao cusDao) {
this.cusDao = cusDao;
}
}
Please let me know any solution.Thanks
By seeing your question what I understood is your trying to make 3 web-service calls and you want to make all three calls in a single transaction.
As you are making a call to another system (Web-service in your case) you don't have control to maintain the transaction.
In your case you can use a Scatter gather router to call three web-services if any route(web-service call) is failed it will throw CompositeRoutingException, you can very well catch this exception in your catch exception strategy.
In your catch exception strategy you need to do the roll back activities (make another web-service call or db call which will fulfill your rollback requirement ).
As per my understanding, you have a three or more webservices calls and some db operations. you want to rollback if any service call fails.
Write a spring bean as below for SpringTransactionFactory and set transationManager property (ref from your applicationContext-persistence.xml)
<spring:beans>
<spring:import resource="classpath:spring-mule.xml"/>
<spring:import resource="classpath:applicationContext-persistence.xml"/>
<spring:bean id = "transactionFactory" class = "org.mule.module.spring.transaction.SpringTransactionFactory">
<spring:property ref="transactionManager" name=""></spring:property>
</spring:bean>
</spring:beans>
And add a tansactionfactory ref to inboundEndpoint as below
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8081/pos/addCustomer" doc:name="HTTP" >
<custom-transaction action="ALWAYS_BEGIN" factory-ref="transactionFactory"/>
</http:inbound-endpoint>
Complete flow will be in single transaction and inclouding dao classes
I have a server that needs to send messages to a separate application. I'm using Spring JmsTemplate, however, I'm having some issues with getting the configuration up and running.
Right now, I'm getting the following exception:
Error creating bean with name 'connectionFactory' defined in ServletContext resource [/WEB-INF/config/application-context.xml]: Invocation of init method failed; nested exception is javax.naming.CommunicationException: Receive timed out [Root exception is java.net.SocketTimeoutException: Receive timed out]
(I can post the full stack trace if you like, but it's just the long version of those nested exceptions.)
The "receive timed out" part makes it sound like it's trying to receive messages, which I don't want to do. Everything here has been pulled together from a couple different examples and SO posts, and I'm having trouble wrapping my head around all of the different parts and what they're doing. In addition to whatever might be causing the error, is there anything I don't need if I'm not receiving messages?
In my JmsQueueSender class (which sends messages):
private JmsTemplate jmsTemplate;
private Destination destination;
public void setConnectionFactory(ConnectionFactory cf) {
jmsTemplate = new JmsTemplate(cf);
}
public void setQueue(Queue queue) {
this.destination = queue;
}
In my application context:
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
<!-- <prop key="java.naming.provider.url">jnp://address.com:port</prop> -->
<prop key="java.naming.factory.url.pkgs">org.jboss.naming:org.jnp.interfaces</prop>
</props>
</property>
</bean>
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="jndiName" value="ConnectionFactory" />
</bean>
<bean id="jmsQueueConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="connectionFactory"/>
<property name="pubSubDomain" value="false" />
</bean>
<bean id="jmsDestinationResolver"
class="org.springframework.jms.support.destination.JndiDestinationResolver">
<property name="jndiTemplate">
<ref bean="jndiTemplate"/>
</property>
<property name="cache">
<value>true</value>
</property>
</bean>
<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate102">
<property name="connectionFactory" ref="jmsQueueConnectionFactory" />
<property name="destinationResolver" ref="jmsDestinationResolver" />
<property name="pubSubDomain" value="false" />
</bean>
<bean id="jmsSender" class="package.JmsQueueSender">
<property name="queue" value="queue/AlertQueueGIAfterSent" />
<property name="connectionFactory" ref="jmsQueueTemplate" />
</bean>