Spring Unit Tests won't roll back when using Atomikos JTA Transaction Manager - spring

We want to use the Atomikos JTA Transaction Manager. We have a unit test which we want to roll back once it completes, thereby leaving the table clean for the next run.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:spring/appContext-test.xml"})
#TransactionConfiguration(transactionManager = "txManager")
public class InboundEmailDaoTest extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired
private InboundEmailDao dao;
#BeforeTransaction
public void beforeTransaction() {
System.out.println("InboundEmailDaoTest: Rows before: " + this.countRowsInTable("myapp.polin2fos_inbound_email"));
}
#AfterTransaction
public void afterTransaction() {
System.out.println("InboundEmailDaoTest: Rows after: " + this.countRowsInTable("myapp.polin2fos_inbound_email"));
}
#Test
public void when_inserting_then_record_is_created() {
String subject = "subject here";
InboundEmail inboundEmail = new InboundEmail();
inboundEmail.setEmailSubject(subject);
//More here...
inboundEmail.setOriginator("originator");
inboundEmail.setOriginSystem("myapp");
inboundEmail.setProcessingStatus("RECEIVED");
inboundEmail.setAttachment("big fat attachment here");
inboundEmail.setAttachmentFilename("Big fat attachment filename here");
int rowsBefore = this.countRowsInTable("myapp.polin2fos_inbound_email");
System.out.println("Rows before: " + rowsBefore);
dao.insert(inboundEmail);
int rowsAfter = this.countRowsInTable("myapp.polin2fos_inbound_email");
System.out.println("Rows after: " + rowsAfter);
assertTrue((rowsAfter == rowsBefore + 1));
}
}
When we run with the Spring-bundled JTA transaction manager configged as below
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
... we get:
Running co.myco.myapp.repository.dao.InboundEmailDaoTest
12:02:22.751 INFO [main][org.springframework.beans.factory.support.DefaultListableBeanFactory] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#13785d3: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0,caseTypeDaoImpl,inboundEmailDaoImpl,inboundEmailRepositoryImpl,propertyPlaceholderConfigurer,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,txManager,dataSource,org.mybatis.spring.mapper.MapperScannerConfigurer#0,sqlSessionFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,caseTypeMapper,inboundEmailMapper]; root of factory hierarchy
12:02:22.798 INFO [main][org.springframework.jdbc.datasource.DriverManagerDataSource] Loaded JDBC driver: oracle.jdbc.OracleDriver
InboundEmailDaoTest: Rows before: 0
12:02:23.770 INFO [main][org.springframework.test.context.transaction.TransactionalTestExecutionListener] Began transaction (1): transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager#8e4805]; rollback [true]
Rows before: 0
12:02:23.832 DEBUG [main][com.myco.repository.mybatis.InboundEmailMapper.insert] ooo Using Connection [oracle.jdbc.driver.T4CConnection#44d990]
12:02:23.835 DEBUG [main][com.myco.repository.mybatis.InboundEmailMapper.insert] ==> Preparing: insert into myapp.polin2fos_inbound_email (EMAIL_SUBJECT, RECEIVED_DATE, ORIGINATOR, ORIGIN_SYSTEM, PROCESSING_STATUS, ATTACHMENT, ATTACHMENT_FILENAME) values (?, sysdate, ?, ?, ?, ?, ?)
12:02:23.888 DEBUG [main][com.myco.repository.mybatis.InboundEmailMapper.insert] ==> Parameters: subject here(String), originator(String), myapp(String), RECEIVED(String), big fat attachment here(String), Big fat attachment filename here(String)
Rows after: 1
12:02:23.927 INFO [main][org.springframework.test.context.transaction.TransactionalTestExecutionListener] Rolled back transaction after test execution for test context [[TestContext#1958cc2 testClass = InboundEmailDaoTest, testInstance = co.myco.myapp.repository.dao.InboundEmailDaoTest#14c28db, testMethod = when_inserting_then_record_is_created#InboundEmailDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration#10e687b testClass = InboundEmailDaoTest, locations = '{classpath:spring/appContext-test.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]
InboundEmailDaoTest: Rows after: 0
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.252 sec
But when we run with the Atomikos Transaction Manager configged as follows:
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="AtomikosTransactionManager" />
<property name="userTransaction" ref="AtomikosUserTransaction" />
</bean>
<!-- ATOMIKOS Transaction-Manager-Specific Setup -->
<bean id="AtomikosTransactionManager"
class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<!-- when close is called, should we force
transactions to terminate or not? -->
<property name="forceShutdown" value="false" />
</bean>
<bean id="AtomikosUserTransaction"
class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
... we get:
Running co.myco.myapp.repository.dao.InboundEmailDaoTest
12:12:42.267 INFO [main][org.springframework.beans.factory.support.DefaultListableBeanFactory] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#13785d3: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0,caseTypeDaoImpl,inboundEmailDaoImpl,inboundEmailRepositoryImpl,propertyPlaceholderConfigurer,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,txManager,AtomikosTransactionManager,AtomikosUserTransaction,dataSource,org.mybatis.spring.mapper.MapperScannerConfigurer#0,sqlSessionFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,caseTypeMapper,inboundEmailMapper]; root of factory hierarchy
12:12:42.310 INFO [main][org.springframework.jdbc.datasource.DriverManagerDataSource] Loaded JDBC driver: oracle.jdbc.OracleDriver
12:12:42.853 INFO [main][com.atomikos.logging.LoggerFactory] Using Slf4J for logging.
12:12:42.854 WARN [main][com.atomikos.icatch.config.UserTransactionServiceImp] No properties path set - looking for transactions.properties in classpath...
12:12:42.855 WARN [main][com.atomikos.icatch.config.UserTransactionServiceImp] transactions.properties not found - looking for jta.properties in classpath...
12:12:42.855 WARN [main][com.atomikos.icatch.config.UserTransactionServiceImp] Failed to open transactions properties file - using default values
12:12:42.893 INFO [main][com.atomikos.persistence.imp.FileLogStream] Starting read of logfile C:\Code\unblocking-workspace-29-05-12\myapp-master\myapp-repository\.\tmlog47.log
12:12:42.893 INFO [main][com.atomikos.persistence.imp.FileLogStream] Done read of logfile
12:12:42.893 INFO [main][com.atomikos.persistence.imp.FileLogStream] Logfile closed: C:\Code\unblocking-workspace-29-05-12\myapp-master\myapp-repository\.\tmlog47.log
12:12:42.899 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING core version: 3.8.0
12:12:42.899 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_file_name = tm.out
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_file_count = 1
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.automatic_resource_registration = true
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.client_demarcation = false
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.threaded_2pc = false
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.serial_jta_transactions = true
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.log_base_dir = .\
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_log_level = WARN
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.max_actives = 50
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.checkpoint_interval = 500
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.enable_logging = true
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.output_dir = .\
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.log_base_name = tmlog
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_file_limit = -1
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.max_timeout = 300000
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.tm_unique_name = 100.100.100.100.tm
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING java.naming.factory.initial = com.sun.jndi.rmi.registry.RegistryContextFactory
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING java.naming.provider.url = rmi://localhost:1099
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.service = com.atomikos.icatch.standalone.UserTransactionServiceFactory
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.force_shutdown_on_vm_exit = false
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.default_jta_timeout = 10000
12:12:42.906 INFO [main][org.springframework.transaction.jta.JtaTransactionManager] Using JTA UserTransaction: com.atomikos.icatch.jta.UserTransactionImp#1568654
12:12:42.906 INFO [main][org.springframework.transaction.jta.JtaTransactionManager] Using JTA TransactionManager: com.atomikos.icatch.jta.UserTransactionManager#18d30fb
InboundEmailDaoTest: Rows before: 1
12:12:43.149 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning NULL!
12:12:43.149 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning NULL!
12:12:43.149 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning NULL!
12:12:43.165 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 entering state: ACTIVE
12:12:43.170 DEBUG [main][com.atomikos.icatch.imp.thread.TaskManager] TaskManager: initializing...
12:12:43.170 INFO [main][com.atomikos.icatch.imp.thread.TaskManager] THREADS: using JDK thread pooling...
12:12:43.176 DEBUG [main][com.atomikos.icatch.imp.thread.TaskManager] THREADS: using executor class com.atomikos.icatch.imp.thread.Java15ExecutorFactory$Executor
12:12:43.177 DEBUG [main][com.atomikos.icatch.imp.thread.Java15ExecutorFactory] (1.5) executing task: com.atomikos.timing.PooledAlarmTimer#160bf50
12:12:43.177 DEBUG [main][com.atomikos.icatch.imp.thread.ThreadFactory] ThreadFactory: creating new thread: Atomikos:0
12:12:43.178 DEBUG [main][com.atomikos.icatch.imp.TransactionServiceImp] Creating composite transaction: 100.100.100.100.tm0000100049
12:12:43.182 INFO [main][com.atomikos.icatch.imp.BaseTransactionManager] createCompositeTransaction ( 300000 ): created new ROOT transaction with id 100.100.100.100.tm0000100049
12:12:43.185 INFO [main][org.springframework.test.context.transaction.TransactionalTestExecutionListener] Began transaction (1): transaction manager [org.springframework.transaction.jta.JtaTransactionManager#ed9f47]; rollback [true]
Rows before: 1
12:12:43.376 DEBUG [main][co.myco.myapp.repository.mybatis.InboundEmailMapper.insert] ooo Using Connection [oracle.jdbc.driver.T4CConnection#96ad7c]
12:12:43.379 DEBUG [main][co.myco.myapp.repository.mybatis.InboundEmailMapper.insert] ==> Preparing: insert into myapp.polin2fos_inbound_email (EMAIL_SUBJECT, RECEIVED_DATE, ORIGINATOR, ORIGIN_SYSTEM, PROCESSING_STATUS, ATTACHMENT, ATTACHMENT_FILENAME) values (?, sysdate, ?, ?, ?, ?, ?)
12:12:43.429 DEBUG [main][co.myco.myapp.repository.mybatis.InboundEmailMapper.insert] ==> Parameters: subject here(String), originator(String), myapp(String), RECEIVED(String), big fat attachment here(String), Big fat attachment filename here(String)
12:12:43.494 INFO [main][org.springframework.beans.factory.xml.XmlBeanDefinitionReader] Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
12:12:43.529 INFO [main][org.springframework.jdbc.support.SQLErrorCodesFactory] SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.533 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 entering state: ABORTING
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 entering state: TERMINATED
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 : stopping timer...
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 : disposing statehandler TERMINATED...
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 : disposed.
12:12:43.536 DEBUG [main][com.atomikos.icatch.imp.CompositeTransactionImp] Ignoring error during event callback
java.lang.IllegalStateException: Transaction no longer active
at com.atomikos.icatch.imp.TxTerminatedStateHandler.rollbackWithStateCheck(TxTerminatedStateHandler.java:106)
at com.atomikos.icatch.imp.CompositeTransactionImp.doRollback(CompositeTransactionImp.java:237)
at com.atomikos.icatch.imp.CompositeTerminatorImp.rollback(CompositeTerminatorImp.java:123)
at com.atomikos.icatch.imp.CompositeTransactionImp.rollback(CompositeTransactionImp.java:346)
at com.atomikos.icatch.imp.CompositeTransactionImp.entered(CompositeTransactionImp.java:373)
at com.atomikos.finitestates.FSMImp.notifyListeners(FSMImp.java:186)
at com.atomikos.finitestates.FSMImp.setState(FSMImp.java:277)
at com.atomikos.icatch.imp.CoordinatorImp.setState(CoordinatorImp.java:429)
at com.atomikos.icatch.imp.CoordinatorImp.setStateHandler(CoordinatorImp.java:286)
at com.atomikos.icatch.imp.CoordinatorStateHandler.rollback(CoordinatorStateHandler.java:764)
at com.atomikos.icatch.imp.ActiveStateHandler.rollback(ActiveStateHandler.java:264)
at com.atomikos.icatch.imp.CoordinatorImp.rollback(CoordinatorImp.java:747)
at com.atomikos.icatch.imp.TransactionStateHandler.rollback(TransactionStateHandler.java:179)
at com.atomikos.icatch.imp.TransactionStateHandler.rollbackWithStateCheck(TransactionStateHandler.java:197)
at com.atomikos.icatch.imp.CompositeTransactionImp.doRollback(CompositeTransactionImp.java:237)
at com.atomikos.icatch.imp.CompositeTerminatorImp.rollback(CompositeTerminatorImp.java:123)
at com.atomikos.icatch.imp.CompositeTransactionImp.rollback(CompositeTransactionImp.java:346)
at com.atomikos.icatch.jta.TransactionImp.rollback(TransactionImp.java:234)
at com.atomikos.icatch.jta.TransactionManagerImp.rollback(TransactionManagerImp.java:524)
at com.atomikos.icatch.jta.UserTransactionImp.rollback(UserTransactionImp.java:141)
at org.springframework.transaction.jta.JtaTransactionManager.doRollback(JtaTransactionManager.java:1037)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:845)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:518)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:292)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:185)
at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:406)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:91)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:236)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:134)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:113)
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 org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:103)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:74)
12:12:43.537 INFO [main][com.atomikos.icatch.imp.CompositeTransactionImp] rollback() done of transaction 100.100.100.100.tm0000100049
In short, it seems Atomikos is ABORTING and TERMINATING our Tx mid flight for no apparent reason. Does anyone have any idea why?

The problem can be in a configuration that is not present in your code snippets.
Datasource should be wrapped into com.atomikos.jdbc.AtomikosDataSourceBean.
If you use Hibernate in your DAO implementation, there are properties that should be set up, like hibernate.transaction.factory_class or hibernate.transaction.manager_lookup_class.

I have a similar set-up and this works for me.
#TransactionConfiguration(transactionManager = "txManager", defaultrollback=true)
You can also set individual #Test methods with #Rollback(true/false)
Depending on what you are calling in your tests you may have to set #Transactional on the class or
#Transactional(propagation=Propagation.REQUIRES_NEW) per transaction #Test method

Related

Transaction rollback in SSM framework problem

software version :jdk 8 spring 4.0 mybatis-3.2.7.jar mybatis-spring-1.2.2.jar ojdbc6.jar oracle 11g
applicationContext.xml:
<context:property-placeholder location="classpath:jdbc.properties" />
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"
id="dataSource">
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="appTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="appTransactionManager" />
junit code:
#RunWith(SpringJUnit4ClassRunner.class)
#TransactionConfiguration(transactionManager = "appTransactionManager", defaultRollback = true)
#Transactional(rollbackFor = Exception.class)
#ContextConfiguration("classpath:applicationContext.xml")
public class GenerateJylshTest {
#Test
#Rollback(true)
public void generateJylshTest() {
String jyjgbh = "4201000000";
GenerateJylsh generator = new GenerateJylsh();
int i;
for(i = 0;i < 3;i++) {
String jylshString = generator.generateJylsh(jyjgbh);
System.out.println(jylshString);
}
int k = 1/0;
}
}
console result:
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
JDBC Connection [oracle.jdbc.driver.T4CConnection#172b013] will be managed by Spring
==> Preparing: SELECT * FROM BIZ_VEH_IS_TEMP_FLOWNUM t WHERE t.JCZ = ? AND t.JCXDM = ?
==> Parameters: 4201000000(String), 42010000001(String)
<== Columns: JCZ, JCXDM, LSH
<== Row: 4201000000, 42010000001, 01000019110800027
<== Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: UPDATE BIZ_VEH_IS_TEMP_FLOWNUM SET LSH = ? WHERE JCZ = ? AND JCXDM = ?
==> Parameters: 01000019110800028(String), 4201000000(String), 42010000001(String)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
01000019110800028
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: SELECT * FROM BIZ_VEH_IS_TEMP_FLOWNUM t WHERE t.JCZ = ? AND t.JCXDM = ?
==> Parameters: 4201000000(String), 42010000001(String)
<== Columns: JCZ, JCXDM, LSH
<== Row: 4201000000, 42010000001, 01000019110800028
<== Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: UPDATE BIZ_VEH_IS_TEMP_FLOWNUM SET LSH = ? WHERE JCZ = ? AND JCXDM = ?
==> Parameters: 01000019110800029(String), 4201000000(String), 42010000001(String)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
01000019110800029
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: SELECT * FROM BIZ_VEH_IS_TEMP_FLOWNUM t WHERE t.JCZ = ? AND t.JCXDM = ?
==> Parameters: 4201000000(String), 42010000001(String)
<== Columns: JCZ, JCXDM, LSH
<== Row: 4201000000, 42010000001, 01000019110800029
<== Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: UPDATE BIZ_VEH_IS_TEMP_FLOWNUM SET LSH = ? WHERE JCZ = ? AND JCXDM = ?
==> Parameters: 01000019110800030(String), 4201000000(String), 42010000001(String)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
01000019110800030
Transaction synchronization rolling back SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
2019-11-08 16:31:09 [main] - [ INFO ] Rolled back transaction after test execution for test context [DefaultTestContext#f316aeb testClass = GenerateJylshTest, testInstance = test.GenerateJylshTest#6aa3a905, testMethod = generateJylshTest#GenerateJylshTest, testException = java.lang.RuntimeException, mergedContextConfiguration = [MergedContextConfiguration#a22cb6a testClass = GenerateJylshTest, locations = '{classpath:applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
2019-11-08 16:31:09 [Thread-1] - [ INFO ] Closing org.springframework.context.support.GenericApplicationContext#4667ae56: startup date [Fri Nov 08 16:31:05 CST 2019]; root of context hierarchy
I used to think that this result code
Transaction synchronization rolling back SqlSession
Transaction synchronization closing SqlSession
means the transaction rollback is already done,but the fact is data still update to the oracle database.
So,I want to konw why.Thanks for any help.

Hibernate sql query format in console

I'm trying to log the sql queries i'm calling from a .xml file. The problem i'm facing is that when i see the log, it's not well formatted. Also, i don't know why it appears repeated...
[main] INFO org.dozer.DozerBeanMapper - Initializing a new instance of dozer bean mapper.
[main] INFO org.dozer.DozerBeanMapper - Initializing a new instance of dozer bean mapper.
[main] INFO org.springframework.orm.hibernate5.HibernateTransactionManager - Using DataSource [org.apache.commons.dbcp2.BasicDataSource#1f03fba0] of Hibernate SessionFactory for HibernateTransactionManager
[main] INFO org.springframework.aop.framework.CglibAopProxy - Unable to proxy method [public final void com.servicios.test.TestRestauranteManager.findProveedoresByIdRestaurante() throws com.servicios.util.exceptions.AlergenosException] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
[main] INFO org.springframework.test.context.transaction.TransactionContext - Began transaction (1) for test context [DefaultTestContext#436bd4df testClass = TestRestauranteManager, testInstance = com.servicios.test.TestRestauranteManager#6848a051, testMethod = findProveedoresByIdRestaurante#TestRestauranteManager, testException = [null], mergedContextConfiguration = [MergedContextConfiguration#149b0577 testClass = TestRestauranteManager, locations = '{classpath:test-applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.hibernate5.HibernateTransactionManager#5740ff5e]; rollback [true]
select restaurant0_."ID_RESTAURANTE" as ID_RESTA1_4_0_, restaurant0_."DESCRIPCION" as DESCRIPC2_4_0_, restaurant0_."ID_CADENA_RESTAURANTE" as ID_CADEN3_4_0_ from "RESTAURANTE" restaurant0_ where restaurant0_."ID_RESTAURANTE"=?
Hibernate: select restaurant0_."ID_RESTAURANTE" as ID_RESTA1_4_0_, restaurant0_."DESCRIPCION" as DESCRIPC2_4_0_, restaurant0_."ID_CADENA_RESTAURANTE" as ID_CADEN3_4_0_ from "RESTAURANTE" restaurant0_ where restaurant0_."ID_RESTAURANTE"=?
binding parameter [1] as [BIGINT] - [0]
I would like to have something like
[main] INFO org.dozer.DozerBeanMapper - Initializing a new instance of dozer bean mapper. [main] INFO org.dozer.DozerBeanMapper -
Initializing a new instance of dozer bean mapper. [main] INFO
org.springframework.orm.hibernate5.HibernateTransactionManager - Using
DataSource [org.apache.commons.dbcp2.BasicDataSource#1f03fba0] of
Hibernate SessionFactory for HibernateTransactionManager [main] INFO
org.springframework.aop.framework.CglibAopProxy - Unable to proxy
method [public final void
com.servicios.test.TestRestauranteManager.findProveedoresByIdRestaurante()
throws com.servicios.util.exceptions.AlergenosException] because it is
final: All calls to this method via a proxy will NOT be routed to the
target instance. [main] INFO
org.springframework.test.context.transaction.TransactionContext -
Began transaction (1) for test context [DefaultTestContext#436bd4df
testClass = TestRestauranteManager, testInstance =
com.servicios.test.TestRestauranteManager#6848a051, testMethod =
findProveedoresByIdRestaurante#TestRestauranteManager, testException =
[null], mergedContextConfiguration =
[MergedContextConfiguration#149b0577 testClass =
TestRestauranteManager, locations =
'{classpath:test-applicationContext.xml}', classes = '{}',
contextInitializerClasses = '[]', activeProfiles = '{}',
propertySourceLocations = '{}', propertySourceProperties = '{}',
contextLoader =
'org.springframework.test.context.support.DelegatingSmartContextLoader',
parent = [null]]]; transaction manager
[org.springframework.orm.hibernate5.HibernateTransactionManager#5740ff5e];
Hibernate: select
p."DESCRIPCION" as "descripcion",
p."ID_PROVEEDOR" as "idProveedor"
from
"RESTAURANTE_PROVEEDOR" rp
inner join
"PROVEEDOR" p
on rp."ID_PROVEEDOR" = p."ID_PROVEEDOR"
where
rp."ID_RESTAURANTE" = ? binding parameter [1] as [BIGINT] - [0]
My log4j.properties is the following:
log4j.rootLogger=INFO, stdout
log4j.logger.org.hibernate=INFO
log4j.logger.org.hibernate.SQL=TRACE
log4j.logger.org.hibernate.type=ALL
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.rootConsola.layout.ConversionPattern=(%d{dd/MM/yyyy-HH:mm:ss}) %-5p: %-40c{1} - %m%n
And in my ApplicationContext.xml I have this
...
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"
p:dataSource-ref="dataSource">
<property name="packagesToScan" value="com.servicios.vo"/>
<property name="mappingLocations">
<list>
<value>classpath*:hibernate/queries/**/*.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
...
Thanks in advance!!
The hibernate.format_sql setting does not apply to Exception reasons when something happens and an Exception is thrown that includes a SQL fragment.
In other words, hibernate.format_sql only applies when Hibernate writes the SQL it's about to execute to the logs, not when it's included as part of some Exception reason.

Data is not written into the XML file from mongodb using Spring Batch, Why?

I am developing Spring Batch MongoDB to XML example. I was successfully developed the application, but I dont see data is getting written into the XML file. Could you please guide me what is the issue ? I dont see any working example yet on the web.
job-report.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd">
<!-- Actual Job -->
<batch:job id="reportJob">
<batch:step id="step1">
<batch:tasklet>
<batch:chunk reader="mongodbItemReader" writer="xmlItemWriter" commit-interval="1">
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
<bean id="mongodbItemReader" class="org.springframework.batch.item.data.MongoItemReader">
<property name="template" ref="mongoTemplate" />
<property name="collection" value="report" />
<property name="targetType" value="com.mkyong.model.Report" />
<property name="query" value="{'_id':{$gt:0} }" />
<property name="sort">
<util:map>
<entry key="id" value="#{T(org.springframework.data.domain.Sort.Direction).ASC}" />
</util:map>
</property>
</bean>
<bean id="xmlItemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
<property name="resource" value="classpath:xml/report.xml" />
<property name="marshaller" ref="reportUnMarshaller" />
<property name="rootTagName" value="record" />
</bean>
<bean id="reportUnMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<value>com.mkyong.model.Report</value>
</property>
</bean>
</beans>
App.java
public class App {
public static void main(String[] args) {
String[] springConfig = { "database.xml", "context.xml", "job-report.xml" };
ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);
JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
Job job = (Job) context.getBean("reportJob");
try {
JobExecution execution = jobLauncher.run(job, new JobParameters());
System.out.println("Exit Status : " + execution.getStatus());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Done");
}
}
Logs from console:
14:58:52.487 [main] DEBUG o.s.b.c.s.c.StepContextRepeatCallback - Preparing chunk execution for StepContext: org.springframework.batch.core.scope.context.StepContext#aa594b
14:58:52.487 [main] DEBUG o.s.b.c.s.c.StepContextRepeatCallback - Chunk execution starting: queue size=0
14:58:52.487 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
14:58:52.487 [main] DEBUG o.s.b.repeat.support.RepeatTemplate - Starting repeat context.
14:58:52.487 [main] DEBUG o.s.b.repeat.support.RepeatTemplate - Repeat operation about to start at count=1
14:58:52.488 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - find using query: { "_id" : { "$gt" : 0}} fields: null for class: class com.mkyong.model.Report in collection: report
14:58:52.488 [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[yourdb]
14:58:52.488 [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Registering Spring transaction synchronization for MongoDB instance yourdb.
14:58:52.488 [main] DEBUG org.mongodb.driver.protocol.query - Sending query of namespace yourdb.report on connection [connectionId{localValue:3, serverValue:53}] to server 127.0.0.1:27017
14:58:52.489 [main] DEBUG org.mongodb.driver.protocol.query - Query completed
14:58:52.489 [main] DEBUG o.s.b.repeat.support.RepeatTemplate - Repeat is complete according to policy and result value.
14:58:52.489 [main] DEBUG o.s.b.c.s.item.ChunkOrientedTasklet - Inputs not busy, ended: true
14:58:52.489 [main] DEBUG o.s.b.core.step.tasklet.TaskletStep - Applying contribution: [StepContribution: read=0, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING]
14:58:52.489 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Participating in existing transaction
14:58:52.490 [main] DEBUG o.s.b.core.step.tasklet.TaskletStep - Saving step execution before commit: StepExecution: id=1, version=5, name=step1, status=STARTED, exitStatus=EXECUTING, readCount=4, filterCount=0, writeCount=4 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=5, rollbackCount=0, exitDescription=
14:58:52.490 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Participating in existing transaction
14:58:52.491 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Initiating transaction commit
14:58:52.491 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Committing resourceless transaction on [org.springframework.batch.support.transaction.ResourcelessTransactionManager$ResourcelessTransaction#a8ee09]
14:58:52.492 [main] DEBUG o.s.b.repeat.support.RepeatTemplate - Repeat is complete according to policy and result value.
14:58:52.492 [main] DEBUG o.s.batch.core.step.AbstractStep - Step execution success: id=1
14:58:52.492 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Creating new transaction with name [org.springframework.batch.core.repository.support.SimpleJobRepository.updateExecutionContext]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
14:58:52.492 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Initiating transaction commit
14:58:52.492 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Committing resourceless transaction on [org.springframework.batch.support.transaction.ResourcelessTransactionManager$ResourcelessTransaction#5b3037]
14:58:52.492 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Creating new transaction with name [org.springframework.batch.core.repository.support.SimpleJobRepository.update]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
14:58:52.494 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Initiating transaction commit
14:58:52.494 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Committing resourceless transaction on [org.springframework.batch.support.transaction.ResourcelessTransactionManager$ResourcelessTransaction#baa89c]
14:58:52.495 [main] DEBUG o.s.batch.core.step.AbstractStep - Step execution complete: StepExecution: id=1, version=7, name=step1, status=COMPLETED, exitStatus=COMPLETED, readCount=4, filterCount=0, writeCount=4 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=5, rollbackCount=0
14:58:52.495 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Creating new transaction with name [org.springframework.batch.core.repository.support.SimpleJobRepository.updateExecutionContext]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
14:58:52.496 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Initiating transaction commit
14:58:52.496 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Committing resourceless transaction on [org.springframework.batch.support.transaction.ResourcelessTransactionManager$ResourcelessTransaction#1f2ebae]
14:58:52.496 [main] DEBUG o.s.b.c.job.flow.support.SimpleFlow - Completed state=reportJob.step1 with status=COMPLETED
14:58:52.496 [main] DEBUG o.s.b.c.job.flow.support.SimpleFlow - Handling state=reportJob.end1
14:58:52.496 [main] DEBUG o.s.b.c.job.flow.support.SimpleFlow - Completed state=reportJob.end1 with status=COMPLETED
14:58:52.497 [main] DEBUG o.s.batch.core.job.AbstractJob - Job execution complete: JobExecution: id=0, version=1, startTime=Tue Jan 10 14:58:52 IST 2017, endTime=null, lastUpdated=Tue Jan 10 14:58:52 IST 2017, status=COMPLETED, exitStatus=exitCode=COMPLETED;exitDescription=, job=[JobInstance: id=0, version=0, Job=[reportJob]], jobParameters=[{}]
14:58:52.497 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Creating new transaction with name [org.springframework.batch.core.repository.support.SimpleJobRepository.update]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
14:58:52.501 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Initiating transaction commit
14:58:52.501 [main] DEBUG o.s.b.s.t.ResourcelessTransactionManager - Committing resourceless transaction on [org.springframework.batch.support.transaction.ResourcelessTransactionManager$ResourcelessTransaction#498b0]
14:58:52.501 [main] INFO o.s.b.c.l.support.SimpleJobLauncher - Job: [FlowJob: [name=reportJob]] completed with the following parameters: [{}] and the following status: [COMPLETED]
Exit Status : COMPLETED
Done
In this example, I do need to manually create xml/report.xml into the classpath. Ideally it should be automatic. Right?
I got the solution to this problem from the link: Complex XML using Spring Batch; StaxEventItemWriter ; Jaxb2Marshaller. Also I should use
<bean id="xmlItemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
<property name="resource" value="file:outputs/report.xml" />
<property name="encoding" value="ISO-8859-1" />
<property name="version" value="1.0" />
<property name="marshaller" ref="reportMarshaller" />
<property name="rootTagName" value="record" />
</bean>

Spring 3.1 Hibernate 4 not rolling back JDBC transaction

I am having trouble setting up a JUnit test that will rollback. I've read a few of these posts here on SO before deciding to write a question, as none seems to be the answer to my problem.
The second test case is failing because data is inserted and persisted in DB from the first test case.
Here's the JUnit test:
package com.company.group.spring.dao;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;
import com.company.group.spring.model.BusObj;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:NAME_OF_CONFIG_FILE.xml"})
#Transactional
#TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
#TestExecutionListeners({TransactionalTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class})
public class PerPartsWCDAOTest {
#Autowired
#Qualifier("myBusObjDAO")
private BusObjDAO busObj_dao;
#Transactional
#Test
public void testInsertRollback() {
try {
BusObj busObj = new BusObj("some data...");
assertNotNull(busObj_dao);
assertNotNull(busObj);
busObj_dao.insert(perPartWC);
}
catch (NullPointerException e) {
e.printStackTrace();
}
}
#Transactional
#Rollback(false)
#Test
public void testInsert() {
BusObj busObj2 = new BusObj("some data...");
busObj_dao.insert(perPartWC2);
}
}
Here's the DAOImpl class (the class I'm trying to test):
package com.company.group.spring.dao;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.company.group.spring.model.BusObj;
#Repository("myBusObjDAO")
public class myBusObjDAOImpl implements myBusObjDAO {
private NamedParameterJdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
#Override
public void insert(BusObj someObj) {
String sql = "insert into TABLE (args...) " +
"VALUES (:named_params....)";
SqlParameterSource paramSource = new BeanPropertySqlParameterSource(someObj);
jdbcTemplate.update(sql, paramSource);
}
}
Part of the relevant config:
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#SERVER:PORT:DB"/>
<property name="username" value="USER"/>
<property name="password" value="XXXXXX"/>
</bean>
Edit: +debug print
2012-12-18 08:50:42,177 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction()] Creating new transaction with name [com.company.group.spring.service.MyClassService.create]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2012-12-18 08:50:42,342 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
2012-12-18 08:50:42,344 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
2012-12-18 08:50:42,361 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Exposing Hibernate transaction as JDBC transaction [org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler#128647a[valid=true]]
2012-12-18 08:50:42,390 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.update()] Executing prepared SQL update
2012-12-18 08:50:42,391 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.execute()] Executing prepared SQL statement [insert into TABLE (args...) VALUES (?, ?, SYSDATE,?, ?, SYSDATE, ?,?, ?)]
2012-12-18 08:50:42,391 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection()] Fetching JDBC Connection from DataSource
2012-12-18 08:50:42,657 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection()] Registering transaction synchronization for JDBC Connection
2012-12-18 08:50:42,671 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement()] SQL update affected 1 rows
2012-12-18 08:50:42,678 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection()] Returning JDBC Connection to DataSource
2012-12-18 08:50:42,688 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback()] Initiating transaction rollback
2012-12-18 08:50:42,688 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doRollback()] Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
2012-12-18 08:50:42,693 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doCleanupAfterCompletion()] Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] after transaction
Update:
I noticed in the log, it is trying to rollback a Hibernate transaction (but this is JDBC). Then noticed the class for "txManager" is currently org.springframework.orm.hibernate4.HibernateTransactionManager, so I experimented with org.springframework.jdbc.datasource.DataSourceTransactionManager and voila, rollback worked. So I think my problem is more specifically how I'm configuring to use Hibernate and JDBC... I still don't know what is wrong.
Your JUnit and DAO classes looks fine.
The problem might be that the connection is auto-committing before the transaction is rolled back. Can you change the dataSource bean to include a defaultAutoCommit property
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#SERVER:PORT:DB"/>
<property name="username" value="USER"/>
<property name="password" value="XXXXXX"/>
<property name="defaultAutoCommit" value="false" />
</bean>
If this is not working can you paste your console logs.
The solution to my problem was specifying the dataSource for the HibernateTransactionManager. Here's the documentation on HibernateTransactionManager.
So I guess it was a mistake not posting how I defined the txManager in the original post.
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
Changed to:
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
<property name="dataSource" ref="dataSource" />
</bean>
I also added <property name="dataSource"><ref local="dataSource"/></property> to the SessionFactory definition, but it doesn't seem necessary if I'm only worried about JdbcTemplate. Suspect it's needed though if HQL is intermixed in there.
Here's what the debug print looks like when it is working. The only difference I saw was this line Returning JDBC Connection to DataSource was absent before initiate rollback
2012-12-19 08:14:29,455 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction()] Creating new transaction with name [com.company.group.spring.service.MyClassService.create]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2012-12-19 08:14:29,512 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
2012-12-19 08:14:29,514 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
2012-12-19 08:14:29,539 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Exposing Hibernate transaction as JDBC transaction [org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler#1289e48[valid=true]]
2012-12-19 08:14:29,558 [main] DEBUG [com.company.group.spring.dao.MyClassDAOImpl.insert()] Session Factory is: org.hibernate.internal.SessionFactoryImpl#1285252
2012-12-19 08:14:29,569 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.update()] Executing prepared SQL update
2012-12-19 08:14:29,570 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.execute()] Executing prepared SQL statement [insert into MY_CLASS (COL1, COL2, COL3, COL4, COL5, COL6, COL7, COL8, COL9) VALUES (?, ?, SYSDATE,?, ?, SYSDATE, ?,?, ?)]
2012-12-19 08:14:29,608 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement()] SQL update affected 1 rows
2012-12-19 08:14:29,611 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback()] Initiating transaction rollback
2012-12-19 08:14:29,612 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doRollback()] Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
2012-12-19 08:14:29,680 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doCleanupAfterCompletion()] Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] after transaction

Hibernate doesn't save edited entities, while saves new ones

I'm facing a weird problem. I'm currently writing a web application based on Spring-MVC 3.2, and Hibernate 4.1.9. I wrote a sample controller with its TestNG unit tests, and everything is fine except for editing. I can see that when saving a new object, it works like a charm, but if I try to edit an existing object, it doesn't get saved without giving out any reason (I'm calling the same method for adding and updating).
The log of adding a new object of type Application
14:26:36.636 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing POST request for [/app/add.json]
14:26:36.637 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /app/add.json
14:26:36.650 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public java.lang.Long com.wstars.kinzhunt.platform.apps.web.AppController.createApp(com.wstars.kinzhunt.platform.model.apps.Application)]
14:26:36.651 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'appController'
14:26:36.821 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Reading [class com.wstars.kinzhunt.platform.model.apps.Application] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:26:36.890 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:26:36.890 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580799968
14:26:36.892 [main] DEBUG c.w.c.dao.hibernate.BaseDaoHibernate - Saving or Updating Object: com.wstars.kinzhunt.platform.model.apps.Application#54fc519b[id=<null>,name=KinzHunt,company=com.wstars.kinzhunt.platform.model.apps.Company#151c2b4[id=1,name=KinzHunt],callbackUrl=http://www.kinzhunt.com/callback/,website=http://www.kinzhunt.com,senderEmail=no-reply#kinzhunt.com,logoUrl=<null>]
14:26:36.892 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:26:36.893 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580799968
14:26:36.893 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:26:36.894 [main] DEBUG o.h.e.def.AbstractSaveEventListener - executing identity-insert immediately
14:26:36.898 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
14:26:36.899 [main] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection
14:26:36.899 [main] DEBUG o.s.j.d.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:h2:mem:platform_test;DB_CLOSE_DELAY=-1]
14:26:36.901 [main] DEBUG org.hibernate.SQL - /* insert com.wstars.kinzhunt.platform.model.apps.Application */ insert into applications (id, callback_url, company_id, logo_url, name, sender_email, website) values (null, ?, ?, ?, ?, ?, ?)
14:26:36.904 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 2
14:26:36.904 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
14:26:36.905 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:26:36.905 [main] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
14:26:36.905 [main] DEBUG org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
14:26:36.926 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Written [2] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:26:36.927 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling
14:26:36.928 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request
While the log for saving an edited object is
14:27:03.398 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing POST request for [/app/1/edit.json]
14:27:03.398 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /app/1/edit.json
14:27:03.401 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public java.lang.Long com.wstars.kinzhunt.platform.apps.web.AppController.editApp(com.wstars.kinzhunt.platform.model.apps.Application,java.lang.Long)]
14:27:03.401 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'appController'
14:27:03.404 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Reading [class com.wstars.kinzhunt.platform.model.apps.Application] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:27:03.409 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:27:03.410 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580800234
14:27:03.411 [main] DEBUG c.w.c.dao.hibernate.BaseDaoHibernate - Saving or Updating Object: com.wstars.kinzhunt.platform.model.apps.Application#1ba4f8a6[id=1,name=KinzHunt,company=com.wstars.kinzhunt.platform.model.apps.Company#6bc06877[id=1,name=KinzHunt],callbackUrl=http://www.kinzhunt.com/callback/,website=http://www.wstars.com/KinzHunt/,senderEmail=no-reply#kinzhunt.com,logoUrl=<null>]
14:27:03.412 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:27:03.412 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580800234
14:27:03.413 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:27:03.422 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:27:03.424 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Written [1] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:27:03.424 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling
14:27:03.425 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request
As you can see, in the second log, no prepared statement is created, and no JDBC connection is opened. My test configuration for the database is like this:
<bean id="targetDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:platform_test;DB_CLOSE_DELAY=-1" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="targetDataSource" />
<property name="packagesToScan">
<list>
<value>com.mypackage.model.*</value>
</list>
</property>
<property name="namingStrategy">
<bean class="com.example.common.config.MyOwnNamingStrategy"/>
</property>
<property name="hibernateProperties">
<map>
<entry key="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<entry key="hibernate.max_fetch_depth" value="1" />
<entry key="hibernate.use_sql_comments" value="true" />
<entry key="hibernate.hbm2ddl.auto" value="update" />
</map>
</property>
<!-- <property key="hibernate.current_session_context_class" value="thread"/> -->
<!-- <property key="hibernate.transaction.factory_class" value="org.hibernate.transaction.JDBCTransactionFactory"/> -->
</bean>
<bean id="h2WebServer" class="org.h2.tools.Server"
factory-method="createWebServer" depends-on="targetDataSource"
init-method="start" lazy-init="false">
<constructor-arg value="-web,-webPort,11111" />
</bean>
My controller code is:
#Controller
public class AppController extends BaseAnnotatedController {
#Autowired
private AppManagementService appManagementService;
#RequestMapping(value="/app/add", method=RequestMethod.POST, consumes={"application/json"})
public #ResponseBody Long createApp(#RequestBody Application app) {
saveApp(app);
return app.getId();
}
#RequestMapping(value="/app/{appId}/edit", method=RequestMethod.POST, consumes={"application/json"})
public #ResponseBody Long editApp(#RequestBody Application app, #PathVariable Long appId) {
if (!appId.equals(app.getId())) {
WSError error = new WSError(ValidationErrorType.GENERIC, "id");
throw new ValidationException(error);
} else {
saveApp(app);
return app.getId();
}
}
#RequestMapping(value="/app/list", method=RequestMethod.GET)
public #ResponseBody List<Application> listApps() {
return appManagementService.listAllApps();
}
#RequestMapping(value="/app/{appId}/get", method=RequestMethod.GET)
public #ResponseBody Application getAppDetails(#PathVariable Long appId) {
return appManagementService.getApplication(appId);
}
private void saveApp(Application app) {
if (isValid(app)) {
appManagementService.saveApp(app);
}
}
public #ResponseBody List<Application> listAllApps() {
return appManagementService.listAllApps();
}
}
My test class is:
#Test
public class AppControllerIntegrationTests extends AbstractContextControllerTests {
private MockMvc mockMvc;
#Autowired
AppController appController;
#Autowired
private AppManagementService appManagementService;
#Autowired
private BaseDao baseDao;
#BeforeClass
public void classSetup() {
Company comp = new Company();
comp.setName("Some Company");
baseDao.saveObject(comp);
}
#BeforeMethod
public void setup() throws Exception {
this.mockMvc = webAppContextSetup(this.wac).build();
}
#Test
public void testAddInvalidAppWebJson() throws Exception {
String appJson = getInvalidApp().toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/add.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
ResultActions resultAction = this.mockMvc.perform(requestBuilder);
resultAction.andExpect(status().isForbidden());
MvcResult mvcResult = resultAction.andReturn();
Exception resolvedException = mvcResult.getResolvedException();
assertTrue(resolvedException instanceof ValidationException);
ValidationException validationException = (ValidationException) resolvedException;
assertEquals(validationException.getErrors().size(), 3);
}
#Test
public void testAddAppWebJson() throws Exception {
Application app = getMockApp();
String appJson = app.toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/add.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc.perform(requestBuilder).andExpect(status().isOk());
}
#Test
public void testEditAppWithWrongIdWebJson() throws Exception {
String appJson = getMockAppWithId().toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/2/edit.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc
.perform(requestBuilder)
.andExpect(status().isForbidden())
.andExpect(
content()
.string("{\"errors\":[{\"errorType\":\"-100\",\"field\":\"id\",\"constraint\":null}],\"objects\":null}"));
}
#Test(dependsOnMethods={"testAddApp", "testAddAppWebJson"})
public void testEditAppWebJson() throws Exception {
Application app = getMockAppWithId();
setAppWebsiteToDifferentOne(app);
String appJson = app.toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/1/edit.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc.perform(requestBuilder).andExpect(status().isOk());
}
#Test
public void testEditInvalidAppWebJson() throws Exception {
Application app = getMockAppWithId();
app.setWebsite("Saba7o 3asal");
String appJson = app.toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/1/edit.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc
.perform(requestBuilder)
.andExpect(status().isForbidden())
.andExpect(
content()
.string("{\"errors\":[{\"errorType\":\"-114\",\"field\":\"website\",\"constraint\":null}],\"objects\":null}"));
}
#Test(dependsOnMethods="testEditAppWebJson")
public void testGetAppDetails() throws Exception {
RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/app/1/get.json");
Application app = getMockAppWithId();
setAppWebsiteToDifferentOne(app);
this.mockMvc.perform(requestBuilder).andExpect(status().isOk())
.andExpect(content().string(app.toJsonString()));
}
}
My service method is:
#Override
#Transactional(readOnly=false)
public void saveApp(Application app) {
baseDao.saveObject(app);
}
All test methods pass, except for the last one, since it's expecting the website of the app to be the one which was edited. Where have I gone wrong?
Need to know which hibernate method is called in saveApp() also make sure your service is annotated with #Transactional.

Resources