I am trying to set up my web app that uses Spring and MyBatis.
Here are the important snippets of code.
Maven dependencies in pom.xml
:
...
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1212.jre7</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
...
And configuration of Spring beans:
@Configuration
@EnableTransactionManagement
public class DatabaseConfiguration {
@Value("classpath:db/mybatis/mybatis-configuration.xml")
private Resource myBatisConfiguration;
@Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://127.0.0.1:5432/ehdb");
dataSource.setUsername(/*my username*/);
dataSource.setPassword(/*my password*/);
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager() {
final DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource());
transactionManager.setValidateExistingTransaction(true);
return transactionManager;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean() {
final SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource());
sqlSessionFactory.setConfigLocation(myBatisConfiguration);
return sqlSessionFactory;
}
@Bean
public SqlSession sqlSession() throws Exception {
return new SqlSessionTemplate(sqlSessionFactoryBean().getObject());
}
}
And here is a service that should call some MyBatis statement in a transactional method:
@Service
public class HelloManagerImpl implements HelloManager {
private final HelloDao helloDao;
public HelloManagerImpl(@Autowired final HelloDao helloDao) {
this.helloDao = helloDao;
}
@Override
@Transactional
public String doSomething() {
helloDao.insertRow(); // a row is inserted into DB table via MyBatis; bean sqlSession is autowired in HelloDao
throw new RuntimeException(); // transaction will be rolled back here
}
}
If I call the method doSomething
, it works as expected. No new row appears in the database table as the transaction is rolled back due to the thrown RuntimeException
.
If I comment out the throw statement and repeat the experiment, a new row appears in the database table. This is the expected behavior again.
And now, if I additionally comment out the @Transactional
annotation and call doSomething()
, the method succeeds and a new row is inserted into the table. It seems that MyBatis creates a transaction for the INSERT
statement automatically if no transaction exists.
I would prefer failing in the last case. If I forget to write the @Transactional
annotation, it is probably a mistake. It would be fine, if an exception is thrown in such case forcing me to fix my code rather than creating some transaction silently.
Is there a way to achive this please?
Thanks for help.