|
|||||||
![]() |
|
|
Thread Tools | Display Modes |
|
#1
|
|||
|
|||
|
Hi Folks,
I'm working on a test class that extends AbstractTransactionalDataSourceSpringContextTests. When my tests exercise database operations through methods in my dao, all works well. But in one of my tests I want to prep the test by first inserting a test row into the db, running a test against it and have everything rollback automatically. The thing is, my inserting of the test row is not done through a dao method, I'm doing it through the hibernateTemplate object available in my test class. This is my onSetUpInTransaction(): Code:
protected void onSetUpInTransaction() throws Exception {
insertedModel = new ModelContent();
insertedModel.setModelName("TestModel");
insertedModel.setModelType("Hatchback");
insertedModel.setModelYear("2007");
insertedModel.setModelDestPrice(43500.00f);
insertedModel.setModelDestPriceAK(44600.00f);
hibernateTemplate.saveOrUpdate(insertedModel);
System.out.println("*** Placed test model in db");
}
Code:
protected void onTearDownInTransaction() throws Exception {
System.out.println("*** Attempt to rollback");
transactionManager.rollback(transactionStatus);
}
Code:
org.springframework.transaction.IllegalTransactionStateException: Transaction is already completed - do not call commit or rollback more than once per transaction at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:556) at org.springframework.test.AbstractTransactionalSpringContextTests.endTransaction(AbstractTransactionalSpringContextTests.java:236) at org.springframework.test.AbstractTransactionalSpringContextTests.onTearDown(AbstractTransactionalSpringContextTests.java:184) at org.springframework.test.AbstractDependencyInjectionSpringContextTests.tearDown(AbstractDependencyInjectionSpringContextTests.java:322) at junit.framework.TestCase.runBare(TestCase.java:130) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:118) at junit.framework.TestSuite.runTest(TestSuite.java:208) at junit.framework.TestSuite.run(TestSuite.java:203) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) |
|
#2
|
|||
|
|||
|
You can only rollback a transaction once (as well as committing).
If it is part of your regular test, it will be automaticaly be rolled back because it is executed in the same transaction (afaik). Else try using the onBeforeTransaction and onTearDownAfterTransaction. Inserting the record in the onBefore and deleting it on the onTearDown. Code:
protected void onSetUpBeforeTransaction() throws Exception {
insertedModel = new ModelContent();
insertedModel.setModelName("TestModel");
insertedModel.setModelType("Hatchback");
insertedModel.setModelYear("2007");
insertedModel.setModelDestPrice(43500.00f);
insertedModel.setModelDestPriceAK(44600.00f);
hibernateTemplate.saveOrUpdate(insertedModel);
System.out.println("*** Placed test model in db");
}
Code:
protected void onTearDownAfterTransaction() throws Exception {
hibernateTemplate.delete(insertedModel);
System.out.println("*** Removed test model from db");
}
Last edited by Marten Deinum; Jul 5th, 2006 at 02:50 AM. |
|
#3
|
|||
|
|||
|
Thanks for the reply...
I did end up manually inserting and removing the test rows in my class's onSetUpInTransaction and onTearDownInTransaction methods. I also noticed that I needed to have this: Code:
setDefaultRollback(false); Thanks again for your help. |
|
#4
|
|||
|
|||
|
Quote:
|
|
#5
|
|||
|
|||
|
That's actually the core of my issue, my insert into the db in the onSetUpInTransaction() method is not being automatically rolled back. I've found that I have to actually remove the objects from the db by hand in my onTearDownInTransaction() method, Spring is doing no rollbacks whatsover. My theory might be that the hibernateTemplate used in my test is not transaction aware. I receive it from my app context in a setter:
Code:
public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
|
|
#6
|
||||
|
||||
|
No - the template uses Hibernate which uses a transaction manager - what is your application context? Sounds like you have a misconfiguration - you can turn on logging and see if the transactions are started/rolledback/committed and if you are indeed using transactions or not.
Also search the forum - this topic has been discussed plenty of times (and there are a lot of code samples also).
__________________
Costin Leau SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source" http://twitter.com/costinl Please use [ c o d e ] [ / c o d e ] tags |
|
#7
|
|||
|
|||
|
Thanks for the reply Costin,
I've been searching through the forum and haven't been able to find anything helpful. I set my spring logs to debug and have the following, I've bolded the important parts: Code:
17:17:51,536 INFO JdbcTransactionObjectSupport:60 - JDBC 3.0 Savepoint class is available 17:17:51,546 DEBUG HibernateTransactionManager:254 - Using transaction object [org.springframework.orm.hibernate3.HibernateTransactionManager$HibernateTransactionObject@1329642] 17:17:51,546 DEBUG HibernateTransactionManager:281 - Creating new transaction with name [null] 17:17:51,636 DEBUG HibernateTransactionManager:449 - Opened new Session [org.hibernate.impl.SessionImpl@8ceeea] for Hibernate transaction 17:17:51,646 DEBUG HibernateTransactionManager:462 - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@8ceeea] 17:17:51,646 DEBUG DriverManagerDataSource:289 - Creating new JDBC Connection to [jdbc:mysql://localhost/mitsu] 17:17:51,716 DEBUG JDBCTransaction:46 - begin 17:17:51,716 DEBUG JDBCTransaction:50 - current autocommit status: true 17:17:51,716 DEBUG JDBCTransaction:52 - disabling autocommit 17:17:51,726 DEBUG HibernateTransactionManager:534 - Exposing Hibernate transaction as JDBC transaction [com.mysql.jdbc.Connection@56860b] 17:17:51,726 DEBUG TransactionSynchronizationManager:162 - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@b122a1] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@7a5a19] to thread [main] 17:17:51,846 DEBUG TransactionSynchronizationManager:162 - Bound value [org.springframework.orm.hibernate3.SessionHolder@1033a6f] for key [org.hibernate.impl.SessionFactoryImpl@f18e8e] to thread [main] 17:17:51,846 DEBUG TransactionSynchronizationManager:214 - Initializing transaction synchronization @@@ About to insert test model @@@ 17:17:51,876 DEBUG CollectionFactory:114 - Creating [java.util.LinkedHashMap] 17:17:51,946 DEBUG CollectionFactory:114 - Creating [java.util.LinkedHashMap] 17:17:51,966 INFO SQLErrorCodesFactory:121 - SQLErrorCodes loaded: [DB2, HSQL, MS-SQL, MySQL, Oracle, Informix, PostgreSQL, Sybase] 17:17:51,966 DEBUG SQLErrorCodesFactory:172 - Looking up default SQLErrorCodes for DataSource [org.springframework.jdbc.datasource.DriverManagerDataSource@7a5a19] 17:17:51,976 DEBUG TransactionSynchronizationManager:137 - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@b122a1] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@7a5a19] bound to thread [main] 17:17:51,976 DEBUG TransactionSynchronizationManager:137 - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@b122a1] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@7a5a19] bound to thread [main] 17:17:51,976 DEBUG SQLErrorCodesFactory:227 - Database product name cached for DataSource [org.springframework.jdbc.datasource.DriverManagerDataSource@7a5a19]: name is 'MySQL' 17:17:51,976 DEBUG SQLErrorCodesFactory:250 - SQL error codes for 'MySQL' found 17:17:51,976 DEBUG TransactionSynchronizationManager:137 - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@1033a6f] for key [org.hibernate.impl.SessionFactoryImpl@f18e8e] bound to thread [main] 17:17:51,976 DEBUG TransactionSynchronizationManager:137 - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@1033a6f] for key [org.hibernate.impl.SessionFactoryImpl@f18e8e] bound to thread [main] 17:17:51,976 DEBUG HibernateTemplate:358 - Found thread-bound Session for HibernateTemplate 17:17:52,076 DEBUG HibernateTemplate:382 - Not closing pre-bound Hibernate Session after HibernateTemplate @@@ Test model has been inserted @@@ @@@ Test the model @@@ 17:17:52,076 DEBUG HibernateTransactionManager:673 - Triggering beforeCompletion synchronization 17:17:52,076 DEBUG HibernateTransactionManager:581 - Initiating transaction rollback 17:17:52,076 DEBUG HibernateTransactionManager:599 - Rolling back Hibernate transaction on Session [org.hibernate.impl.SessionImpl@8ceeea] 17:17:52,076 DEBUG JDBCTransaction:132 - rollback 17:17:52,127 DEBUG JDBCTransaction:173 - re-enabling autocommit 17:17:52,127 DEBUG JDBCTransaction:143 - rolled back JDBC Connection 17:17:52,137 DEBUG HibernateTransactionManager:697 - Triggering afterCompletion synchronization 17:17:52,137 DEBUG TransactionSynchronizationManager:265 - Clearing transaction synchronization 17:17:52,137 DEBUG TransactionSynchronizationManager:185 - Removed value [org.springframework.orm.hibernate3.SessionHolder@1033a6f] for key [org.hibernate.impl.SessionFactoryImpl@f18e8e] from thread [main] 17:17:52,177 DEBUG TransactionSynchronizationManager:185 - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@b122a1] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@7a5a19] from thread [main] 17:17:52,187 DEBUG HibernateTransactionManager:659 - Closing Hibernate Session [org.hibernate.impl.SessionImpl@8ceeea] after transaction 17:17:52,187 DEBUG SessionFactoryUtils:785 - Closing Hibernate Session Code:
protected void onSetUpInTransaction() throws Exception {
System.out.println("@@@ About to insert test model @@@");
insertedModel = new ModelContent();
insertedModel.setModelName("TestModel");
insertedModel.setModelType("Hatchback");
insertedModel.setModelYear("2007");
insertedModel.setModelDestPrice(43500.00f);
insertedModel.setModelDestPriceAK(44600.00f);
hibernateTemplate.saveOrUpdate(insertedModel);
System.out.println("@@@ Test model has been inserted @@@");
}
Code:
<beans> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost/mitsu"/> <property name="username" value="root"/> <property name="password" value="***"/> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mappingResources"> <list> <value>com/organic/mitsu/hib/ModelContent.hbm.xml</value> <value>com/organic/mitsu/hib/Trim.hbm.xml</value> <value>com/organic/mitsu/hib/Accessory.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.cache.use_query_cache">true</prop> </props> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> <property name="dataSource" ref="dataSource"/> </bean> <bean id="modelDao" class="com.organic.mitsu.dao.ModelDaoImpl"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <bean id="modelServiceTarget" class="com.organic.mitsu.service.ModelServiceImpl" abstract="false"> <property name="modelDao" ref="modelDao"/> </bean> <bean id="modelManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"><ref local="transactionManager"/></property> <property name="target"><ref local="modelServiceTarget"/></property> <property name="transactionAttributes"> <props> <prop key="list*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="updateModel">PROPAGATION_REQUIRED</prop> </props> </property> </bean> </beans> |
|
#8
|
|||
|
|||
|
Little update on this. After some forum searching, I switched my MySql table to use the InnoDB, this resolved the issues. BUT, I work with a SQL Server instance on my app at work and I could have sworn I had the same issues. So I'll take a look at this first thing tomorrow. Does anybody know if SQL Server has the same type of transaction requirements as MySQL, or does SQL Server default to enabling transactions? Thanks
|
|
#9
|
|||
|
|||
|
Quote:
|
|
#10
|
|||
|
|||
|
Hi Folks,
Well, I'm not sure what I had done, but this issue is officially resolved I might have had something sublty off in one of my configurations or test classes. I hadn't taken a look at this issue in a few days, I think giving it a break and returning to it with a fresh perspective helped. Once again, thank you guys for all your help.- Mike |
![]() |
| Thread Tools | |
| Display Modes | |
|
|