Hi all I have done an application configuration using jsf ,spring 3.0,hybernate + JPA and atomikos for XA transcation management and mysql is my backend,here every thing is working fine however insert operation, when exception is throwing the transcation should rollback,but it is not happening!! here is a small flow for our application i am using jsfmanagedbean to cal my servive,from my service class my transcation will start
TextileUIBean.java
package com.textile.web; public class TextileUIBean extends BaseManagedBean implements Serializable, { public insertPaymentDetails() { PaymentDetails PaymentDetails=new PaymentDetails(); // values are hard coded ans only two propereties only using PaymentDetails.setCustomerName("Manikandan"); PaymentDetails.setAmount(1000); getTextileManager().insertPaymentDetails(PaymentDetails); } public ITextileManager getTextileManager() { textileManager = (ITextileManager) getBean("textileManager"); return textileManager; } } service class
package com.textile.web
public interface ITextileManager
{
public void insertPaymentDetails(PaymentDetails PaymentDetails);
}
package com.textile.web
public class TextileManager implements ITextileManager
{
ITextileBusiness TextileBusiness ;
public void setTextileBusiness(ITextileBusiness textileBusiness) {
this.textileBusiness = textileBusiness;
}
void insertPaymentDetails(PaymentDetails PaymentDetails)
{
TextileBusiness.insertPaymentDetails(PaymentDetails);
}
and my business class is
package com.textile.web
public interface ITextileBusiness
{
public void insertPaymentDetails(PaymentDetails PaymentDetails);
}
package com.textile.web
public class TextileBusiness implements ITextileBusiness
{
ITextileDao textileDao;
public void setTextileDao(ITextileDao textileDao) {
this.textileDao = textileDao;
}
void insertPaymentDetails(PaymentDetails ormPaymentTable)
{
OrmPaymentTable ormPaymentTable= OrmPaymentTable();
ormPaymentTable.setCustomerName(PaymentDetails.getCustomerName());
ormPaymentTable.setAmount(PaymentDetails.getAmount(););
textileDao.insertPaymentDetails(ormPaymentTable);
int a=0;
if(a==0)
throw new BusinessException("Transcation Rollback");
}
}
and my dao class is
package com.textile.web
public interface IPaymentsDao {
public void insertPaymentDetails(OrmPaymentTable ormPaymentTable);
}
package com.textile.web
public class PaymentsDao implements IPaymentsDao
{
void insertPaymentDetails(OrmPaymentTable ormPaymentTable)
{
this.getJpaTemplate().persist(ormPaymentTable);
after this line the record is insertinf into table
}
}
my FacesConfig.xml is
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>en</supported-locale>
</locale-config>
<message-bundle>Messages</message-bundle>
</application>
<managed-bean> <managed-bean-name>textileUIBean</managed-bean-name> <managed-bean-class>com.textile.web.TextileUIBean</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
</managed-bean>
and my applicationConfig.xml file is
<beans:bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean" >
<beans: property name="jndiName">
<beans: value>java:comp/env/jdbc/textWeb</beans:value>
</beans: property>
<beans: property name="resourceRef">
<beans:value>true</beans:value>
</beans: property>
</beans: bean>
<beans: bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
<beans: property name="entityManagerFactory">
<beans: ref bean="entityManagerFactory" />
</beans: property>
</beans: bean>
<beans: bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- hidden by shiju because we need one datasource support its in prsistence.xml !-->
<beans: property name="dataSource">
<beans: ref bean="dataSource" />
</beans: property>
<beans: property name="persistenceUnitName" value="payhub" />
<beans: property name="jpaVendorAdapter">
<beans:bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<beans: property name="generateDdl" value="false" />
<beans: property name="showSql" value="true" />
<beans: property name="databasePlatform" value="${database.target}" />
</beans: bean>
</beans: property>
<beans: property name="persistenceXmlLocation">
<beans: value>classpath:META-INF/persistence.xml</beans:value>
</beans: property>
</beans: bean>
<beans:bean id="textileManager"
class=" com.textile.web.TextileManager">
<beans: property name="textileBusiness" ref="textileBusiness" />
</beans: bean>
<beans: bean id="textileBusiness" class="com.textile.web.TextileBusiness">
<beans: property name="textileDao" ref="textileDao" />
</beans: bean>
<beans: bean id="textileDao" class="com.textile.web.textileDao">
<beans: property name="jpaTemplate">
<beans: ref bean="jpaTemplate"/>
</beans: property>
</beans: bean>
<aop:config>
<aop:pointcut id="fooServiceOperation" expression="execution(* com.textile.web.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<beans: bean id="atomikosTransactionManager"
class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init"
destroy-method="close">
<beans: property name="forceShutdown" value="true" />
<beans: property name="startupTransactionService" value="true" />
</beans:bean>
<beans:bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<beans: property name="transactionTimeout">
<beans: value>3000</beans:value>
</beans: property>
</beans:bean>
<beans: bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<beans: property name="transactionManager">
<beans: ref bean="atomikosTransactionManager" />
</beans: property>
<beans: property name="userTransaction">
<beans: ref bean="atomikosUserTransaction"/>
</beans: property>
<beans: property name="rollbackOnCommitFailure" value="true">
</beans: property>
</beans: bean>
and orm.xml file is
<entity class="OrmPaymentTable" name="OrmPaymentTable">
<table name="ta_payment" />
<attributes>
<id name="paymentId">
<column name="USER_ID" />
<generated-value strategy="AUTO" />
</id>
<basic name="customerName">
<column name="CUST_NAME" length="50" />
</basic>
<basic name="amount">
<column name="AMOUNT" length="50" />
</basic>
</attributes>
</entity>
<persistence-unit name="payhub" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:comp/env/jdbc/textWeb</jta-data-source>
<mapping-file>META-INF/orm.xml</mapping-file>
<class>com.textile.web.OrmPaymentTable</class>
<properties>
<property name="hibernate.transaction.manager_lookup_class"
value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup"/>
<property name="hibernate.transaction.factory_class"
value="org.hibernate.transaction.JTATransactionFactory" />
</properties>
</persistence-unit>
</persistence>
and i configure jndi in meta-inf/context.xml
<Context>
<Transaction factory="com.atomikos.icatch.jta.UserTransactionFactory"/>
<Resource name="jdbc/textWeb" auth="Container"
driverClassName="com.mysql.jdbc.Driver" user="root" password="root"
type="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" factory="com.mysql.jdbc.jdbc2.optional.MysqlDataSourceFactory"
url="jdbc:mysql://localhost:3306/textWeb" explicitUrl="true"
pinGlobalTxToPhysicalConnection="true">
</Resource>
</Context>
web.xml
<resource-ref>
<description>PaymentsDatabase</description>
<res-ref-name>jdbc/textWeb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
I trace the log.. see my transcation log details
78 [main] INFO atomikos - USING core version: 3.6.4
78 [main] INFO atomikos - USING com.atomikos.icatch.console_file_name = tm.out
78 [main] INFO atomikos - USING com.atomikos.icatch.console_file_count = 1
78 [main] INFO at开发者_开发问答omikos - USING com.atomikos.icatch.automatic_resource_registration = true
78 [main] INFO atomikos - USING com.atomikos.icatch.client_demarcation = false
78 [main] INFO atomikos - USING com.atomikos.icatch.threaded_2pc = true
78 [main] INFO atomikos - USING com.atomikos.icatch.serial_jta_transactions = false
78 [main] INFO atomikos - USING com.atomikos.icatch.log_base_dir = .\
94 [main] INFO atomikos - USING com.atomikos.icatch.console_log_level = WARN
94 [main] INFO atomikos - USING com.atomikos.icatch.max_actives = 50
94 [main] INFO atomikos - USING com.atomikos.icatch.checkpoint_interval = 500
94 [main] INFO atomikos - USING com.atomikos.icatch.enable_logging = false
94 [main] INFO atomikos - USING com.atomikos.icatch.output_dir = .\
94 [main] INFO atomikos - USING com.atomikos.icatch.log_base_name = tmlog
94 [main] INFO atomikos - USING com.atomikos.icatch.console_file_limit = 0
94 [main] INFO atomikos - USING com.atomikos.icatch.max_timeout = 300000
94 [main] INFO atomikos - USING com.atomikos.icatch.tm_unique_name = PaymentsTransactions
94 [main] INFO atomikos - USING java.naming.factory.initial = com.sun.jndi.rmi.registry.RegistryContextFactory
94 [main] INFO atomikos - USING java.naming.provider.url = rmi://localhost:1099
94 [main] INFO atomikos - USING com.atomikos.icatch.service = com.atomikos.icatch.standalone.UserTransactionServiceFactory
94 [main] INFO atomikos - USING com.atomikos.icatch.force_shutdown_on_vm_exit = false
94 [main] INFO atomikos - USING com.atomikos.icatch.default_jta_timeout = 10000
INFO - JtaTransactionManager.checkUserTransactionAndTransactionManager(469) | Using JTA UserTransaction: com.atomikos.icatch.jta.UserTransactionImp@16a6027
INFO - JtaTransactionManager.checkUserTransactionAndTransactionManager(480) | Using JTA TransactionManager: com.atomikos.icatch.jta.UserTransactionManager@e68513
DEBUG - NameMatchTransactionAttributeSource.addTransactionalMethod(94) | Adding transactional method [*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT]
DEBUG - AbstractPlatformTransactionManager.getTransaction(365) | Creating new transaction with name [com.evolvus.payments.manager.IPaymentsManager.findColumnChartDisplayByGateWays]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
40500 [http-8080-Processor24] WARN atomikos - Attempt to create a transaction with a timeout that exceeds com.atomikos.icatch.max_timeout - truncating to: 300000
40641 [http-8080-Processor24] INFO atomikos - THREADS: using JDK thread pooling...
40703 [http-8080-Processor24] INFO atomikos - createCompositeTransaction ( 3000000 ): created new ROOT transaction with id PaymentsTransactions0000100688
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
DEBUG - AbstractPlatformTransactionManager.processRollback(850) | Participating transaction failed - marking existing transaction as rollback-only
DEBUG - JtaTransactionManager.doSetRollbackOnly(1060) | Setting JTA transaction rollback-only
49110 [http-8080-Processor24] INFO atomikos - setRollbackOnly() called for transaction PaymentsTransactions0000100688
DEBUG - AbstractPlatformTransactionManager.processRollback(843) | Initiating transaction rollback
49172 [http-8080-Processor24] INFO atomikos - afterCompletion ( STATUS_ROLLEDBACK ) called on Synchronization: org.hibernate.transaction.CacheSynchronization
49172 [http-8080-Processor24] INFO atomikos - afterCompletion ( STATUS_ROLLEDBACK ) called on Synchronization: org.hibernate.ejb.EntityManagerImpl$1@1f6e48a
49172 [http-8080-Processor24] INFO atomikos - rollback() done of transaction PaymentsTransactions0000100688
could you help me ?
Clearly your database insert is not happening within the scope of your transaction manager's current transaction.
A few ideas:
1) Maybe its just not in your posting, but I don't see the Spring @Transactional annotation on your service class. What is your strategy for controlling transaction boundaries?
2) Because you are using JNDI, we don't get to see your data source, but if you are using Atomikos, you should be using their XA aware pooling data source. Are you?
3) You should increase Atomikos normal logging to DEBUG to see exactly which SQL commands it is handling.
4) Atomikos keeps transaction logs that are outside your normal log files. These are used for recover and other purposes. You should also check these for clues.
Hope this helps.
Update:
MySQL has some limitations with XA transactions as you can here about here. Try this configuration out within your context.xml and at least see if it works. It uses an XA aware (but not XA capable) data source from Atomikos. If this works then you can go from there:
<Transaction factory="com.atomikos.icatch.jta.UserTransactionFactory" />
and the define the JNDI data source for injection into your entity manager:
<Resource name="jdbc/myDataSource" auth="Container"
factory="org.apache.naming.factory.BeanFactory"
type="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean"
uniqueResourceName="myMySqlDatabase" driverClassName="com.mysql.jdbc.Driver"
url="......" user="....." password="...."
maxPoolSize="20" reapTimeout="300" />
精彩评论