Atomikos Forum |
|
I am using JPA and this is my configuration:
@Entity @Table(name = "EntityA") public class EntityA implements Serializable { @Id private Long id; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "EntityB_ID", nullable = false) private EntityB entityB; ... } @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "entityB_type", discriminatorType = DiscriminatorType.STRING) @Table(name = "EntityB") public abstract class EntityB implements Serializable { @Id private Long id; @Column(name = "name") private String name; @Column(name = "entityB_type") private String entityB_type; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "EntityC_ID", nullable = false) private EntityC entityC; ... } @Entity @DiscriminatorValue("somevalue") public class EntityB_Special extends EntityB implements Serializable { @Column(name = "some_special_value") private String someSpecialValue; } @Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "entityC_type", discriminatorType = DiscriminatorType.STRING) @Table(name = "EntityC") public abstract class EntityC implements Serializable { @Id private Long id; @Column(name = "entityC_type") private String entityC_type; .... } @Entity @DiscriminatorValue("anothervalue") public class EntityC_Special extends EntityC implements Serializable { @Column(name = "another_special_value") private String anotherSpecialValue; } There are MySql foreign key constraints linking EntityA -> EntityB -> EntityC with database cascades set as "NO ACTION" since cascades are handled via hibernate. This is my JTA.properties file: com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory com.atomikos.icatch.console_file_name = EntityTxn.out com.atomikos.icatch.log_base_name = EntityTxnlog com.atomikos.icatch.console_log_level = WARN com.atomikos.icatch.log_base_dir = ${catalina.base}/logs com.atomikos.icatch.output_dir = ${com.atomikos.icatch.log_base_dir} com.atomikos.icatch.tm_unique_name = Entity com.atomikos.icatch.max_actives = 100 This is my spring transaction configuration: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close"> <property name="forceShutdown" value="true"/> </bean> <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"> <property name="transactionTimeout" value="300"/> </bean> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager" ref="atomikosTransactionManager"/> <property name="userTransaction" ref="atomikosUserTransaction"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans> This is my database configuration: <bean id="entityDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"><value>${master.jdbc.driver}</value></property> <property name="url"><value>${jdbc.url}</value></property> <property name="username"><value>${jdbc.user}</value></property> <property name="password"><value>${jdbc.password}</value></property> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="entityDataSource"/> <property name="annotatedClasses"> <list> <value>com.somepackage.EntityA</value> <value>com.somepackage.EntityB</value> <value>com.somepackage.EntityC</value> <value>com.somepackage.EntityB_Special</value> <value>com.somepackage.EntityC_Special</value> </list> </property> <property name="entityCacheStrategies"> <props> <prop key="com.somepackage.EntityA">read-only</prop> <prop key="com.somepackage.EntityB">read-only</prop> <prop key="com.somepackage.EntityC">read-only</prop> </props> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.use_sql_comments">true</prop> <prop key="hibernate.use_outer_join">false</prop> <prop key="hibernate.query.substitutions">true=1 false=0</prop> <prop key="hibernate.transaction.factory_class">com.atomikos.icatch.jta.hibernate3.AtomikosJTATransactionFactory</prop> <prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop> <prop key="hibernate.connection.isolation">2</prop> <prop key="hibernate.current_session_context_class">jta</prop> <prop key="hibernate.connection.autocommit">false</prop> <prop key="hibernate.cache.region.factory_class">net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory</prop> <prop key="net.sf.ehcache.configurationResourceName">${ehcache.config.file}</prop> <prop key="hibernate.cache.use_second_level_cache">false</prop> </props> </property> </bean> I have a simple repository class as: @Repository public class EntityARepositoryImpl implements EntityARepository { /** Session factory */ @Autowired private SessionFactory sessionFactory; /** * {@inheritDoc} */ @Override public Long save(EntityA entityA) { return (Long) sessionFactory.getCurrentSession().save(entityA); } } I have a very simple code to try and save EntityA which is: @Autowired EntityARepositoryImpl entityARepositoryImpl; EntityA entityA = new EntityA(); EntityB_Special entityBSpecial = new EntityB_Special(); EntityC_Special entityCSpecial = new EntityC_Special(); entityCSpecial.setxxx ... entityBSpecial.setEntityC(entityCSpecial); entityBSpecial.setName("A very long value"); ... entityA.setEntityB(entityBSpecial); entityARepositoryImpl.save(entityA); Lets say the user enters a very long value for the "name" field in entityB and there is an exception. The exception thrown is as follows: org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Transaction set to rollback only ... 10-12-28 14:48:00,600 [http-8080-2] Unexpected error in beforeCompletion: org.hibernate.exception.DataException: Could not execute JDBC batch update at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:102) .... Caused by: java.sql.BatchUpdateException: Data truncation: Data too long for column 'name' at row 1 at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2020) .... The issue is when I check the tables, Entity A and Entity B tables have no data but Entity C's data has been committed resulting in a partial commit eventhough the transaction has rolled back. This is similar to an issue raised by another post: default82df.html?community.6.542.11 However this issue still persists. I am using version 3.6.6 of the atomikos release. I have attached the transaction log. Please help. Thanks Dilshan
Transaction log:
10-12-28 14:31:07,407 [main] Starting read of logfile D:\Software\apache-tomcat-6.0.29\logs\entityTmlog86.log 10-12-28 14:31:07,407 [main] Done read of logfile 10-12-28 14:31:07,408 [main] Logfile closed: D:\Software\apache-tomcat-6.0.29\logs\entityTmlog86.log 10-12-28 14:34:57,716 [http-8080-6] Unexpected error in beforeCompletion: org.hibernate.exception.DataException: Could not execute JDBC batch update at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:102) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275) at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:114) at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:109) at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:244) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2395) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2858) at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79) at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:267) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:259) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:178) at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206) at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375) at org.hibernate.transaction.CacheSynchronization.beforeCompletion(CacheSynchronization.java:88) at com.atomikos.icatch.jta.Sync2Sync.beforeCompletion(Sync2Sync.java:73) at com.atomikos.icatch.imp.TransactionStateHandler.commit(TransactionStateHandler.java:253) at com.atomikos.icatch.imp.CompositeTransactionImp.doCommit(CompositeTransactionImp.java:511) at com.atomikos.icatch.imp.CompositeTerminatorImp.commit(CompositeTerminatorImp.java:138) at com.atomikos.icatch.jta.TransactionImp.commit(TransactionImp.java:317) at com.atomikos.icatch.jta.TransactionManagerImp.commit(TransactionManagerImp.java:613) at com.atomikos.icatch.jta.UserTransactionImp.commit(UserTransactionImp.java:168) at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1009) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) at $Proxy77.addNewStoreBasedOfferCampaign(Unknown Source) at entityARepositoryImpl.save(entityARepositoryImpl.java:5) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:37) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:244) at javax.management.modelmbean.RequiredModelMBean.invokeMethod(RequiredModelMBean.java:1074) at javax.management.modelmbean.RequiredModelMBean.invoke(RequiredModelMBean.java:955) at org.springframework.jmx.export.SpringModelMBean.invoke(SpringModelMBean.java:90) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:836) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:761) at org.rydzewski.jmxconsole.action.CallOperationAction.doEexecute(CallOperationAction.java:48) at org.rydzewski.struts.action.BaseAction.execute(BaseAction.java:57) at org.apache.struts.chain.commands.servlet.ExecuteAction.execute(ExecuteAction.java:53) at org.apache.struts.chain.commands.AbstractExecuteAction.execute(AbstractExecuteAction.java:64) at org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:48) at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190) at org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:304) at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190) at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:280) at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1858) at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:459) at javax.servlet.http.HttpServlet.service(HttpServlet.java:637) at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.rydzewski.common.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) at java.lang.Thread.run(Thread.java:619) Caused by: java.sql.BatchUpdateException: Data truncation: Data too long for column 'name' at row 1 at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2020) at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1451) at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70) at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268) ... 73 more
ehcache configuration:
<defaultCache maxElementsInMemory="10000" memoryStoreEvictionPolicy="LRU" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" > </defaultCache> <cache name="somepackage.EntityA" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="500" timeToLiveSeconds="5000" overflowToDisk="false" copyOnRead="false" copyOnWrite="false"> </cache> <cache name="somepackage.EntityB" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="500" timeToLiveSeconds="5000" overflowToDisk="false" copyOnRead="false" copyOnWrite="false"> </cache> <cache name="somepackage.EntityC" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="500" timeToLiveSeconds="5000" overflowToDisk="false" copyOnRead="false" copyOnWrite="false"> </cache>
But it should not insert any stuff into any of the tables if it fails (even its a database issue, might be a tx locking issue e.g. too) - the tx should rollback all changes made to all tables, right - shouldn't it?
@dilshan: I tried to make a small test to verify your post - but hibernate does not even have success in creating the schema - your code postet seems to be wrong or incomplete. Can you please make some "small!" maven2 test project which does show the problem? Let ehcache etc. out to make the case smallest as possible.
@Torsten: you have a point.
@dilshan: I think the problem might be JPA again: http://www.atomikos.com/Documentation/HibernateIntegration#With_JPA HTH
Hi Guys,
Thank you for your feedback. I was able to resolve this issue. The issue was that I was using the Spring org.springframework.jdbc.datasource.DriverManagerDataSource with the atomikos transaction manager which was not correct. I used the com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean instead and now things are working fine |