Я пытаюсь настроить мое веб-приложение, использующее Spring и MyBatis.Выбросить исключение из-за отсутствия @Transactional с Spring и MyBatis
Вот важные фрагменты кода.
Maven зависимости в 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>
...
и конфигурация Spring фасоли:
@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());
}
}
А вот это услуга, которая должна вызывать некоторое MyBatis заявления в транзакционной методе:
@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
}
}
Если я вызываю метод doSomething
, он работает как ожидалось. Никакая новая строка не появляется в таблице базы данных, так как транзакция откатывается из-за броска RuntimeException
.
Если я прокомментирую инструкцию throw и повторю эксперимент, в таблице базы данных появится новая строка. Это ожидаемое поведение снова.
И теперь, если я дополнительно прокомментирую аннотацию @Transactional
и позвонил doSomething()
, метод будет успешным, и новая таблица будет вставлена в таблицу. Кажется, что MyBatis автоматически создает транзакцию для оператора INSERT
, если транзакция не существует.
В последнем случае я предпочел бы потерпеть неудачу. Если я забуду написать аннотацию @Transactional
, это, вероятно, ошибка. Было бы замечательно, если бы исключение в таком случае заставляло меня исправлять мой код, а не создавать транзакцию молча.
Есть ли способ достичь этого, пожалуйста?
Спасибо за помощь.
Поддерживает ли ваша транзакция db? Как вы знаете, движок MYISAM не делает. – Blank
@Forward Да, я использую Postgres 9.6. – Cimlman