Откат транзакции на Spring тестах JDBC
Я пытаюсь выполнить откат транзакций JDBC при использовании Spring -test без успеха. Когда я запускаю следующее, обновление SQL всегда выполняется.
package my.dao.impl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
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 javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Statement;
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
@ContextConfiguration(locations={"classpath:ApplicationContext-test-DAOs.xml"})
@TransactionConfiguration(defaultRollback = true)
public class ConfirmationMatchingDAOImplTest {
@Autowired
private DataSource dataSource;
@Test
public void shouldInsertSomething() throws Exception {
final Connection connection = dataSource.getConnection();
final Statement statement = connection.createStatement();
statement.executeUpdate("insert into TEST_INSERT values (1, 'hello')");
statement.close();
connection.close();
}
}
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://makeitfunky:1490;databaseName=fonzie"/>
<property name="username" value="ralph"/>
<property name="password" value="p0n1es_R_kew1"/>
</bean>
Что я делаю неправильно?
Кроме того, я использую слишком много аннотаций? Могу ли я сделать его немного чище?
Ответы
Ответ 1
Если вы явно не настраиваете прослушиватели выполнения тестов с помощью аннотации @TestExecutionListeners
, Spring настраивается по умолчанию DependencyInjectionTestExecutionListener
, DirtiesContextTestExecutionListener
и TransactionalTestExecutionListener
. TransactionalTestExecutionListener
обеспечивает выполнение транзакционного теста с использованием семантики отката по умолчанию. Явным образом объявляя @TestExecutionListeners
в вашем тестовом классе и опуская TransactionalTestExecutionListener
из списка прослушивателей, вы отключите поддержку транзакций.
Вы также должны добавить аннотацию @Transactional
на уровне класса или метода.
Вы также должны использовать DataSourceUtils, чтобы получить транзакционное соединение, управляемое DataSourceTransactionManager.
Ответ 2
Если вы используете метод non-xml, это прекрасно работает с версии 3.1
@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestDbConfig.class, SomeService.class})
public class SomeTest {
@Inject
private SomeService someService;
@PersistenceContext
private EntityManager em;
@Test
public void someTest() {}
Затем тестовая конфигурация принимает эту форму. Обратите внимание на @EnableTransactionManagement и на то, что вы можете объявить глобальный тест defaultRollback. Это особенно полезно для крупных проектов.
@Configuration
@PropertySource(value = "classpath:app.properties")
@EnableTransactionManagement
@TransactionConfiguration(defaultRollback = true)
public class TestDbConfig {
//read the parameters from properties
@Value("${hibernate.dialect:unset}")
private String hibernateDialect;
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public PlatformTransactionManager transactionManager() {
//for example
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
return transactionManager;
}
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
//set the datasource
//set the JpaVendorAdapter
//set the packagesToScan
return some sort of LocalContainerEntityManagerFactoryBean;
}
@Bean
DataSource dataSource() {
return dataSource from jndi or a DriverManagerDataSource();
}
}
Ответ 3
добавьте эту аннотацию, и в тестовых случаях откат не будет:
@TransactionConfiguration(defaultRollback=false)
Моя аннотация выглядит следующим образом:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/../applicationContext.xml" })
@TransactionConfiguration(defaultRollback=true)
public class DBCreatorTest {
Ответ 4
Может быть, потому что у вас нет метода @Transactional
для тестового метода?
Ответ 5
При использовании аннотации @Transactional в Spring вы должны добавить следующую строку в конфигурационный файл Spring:
<tx:annotation-driven transaction-manager="transactionManager"/>
Свойство manager-manager содержит ссылку на диспетчер транзакций bean, определенный в файле конфигурации Spring. Этот код сообщает Spring использовать аннотацию @Transaction при применении перехватчика транзакций. Без него аннотация @Transactional игнорируется, в результате в вашем коде не используется транзакция.
Источник на веб-сайте IBM
Ответ 6
Дополнительная информация:
для этой строки
<tx:annotation-driven transaction-manager="transactionManager"/>
Значением по умолчанию атрибута transaction-manager
является "transactionManager".
Этот атрибут требуется, только если bean id/name transactionManager не является "transactionManager".
Поэтому вам просто нужно установить:
<tx:annotation-driven />
Ответ 7
Вам нужно добавить @Transactional
на уровне класса.
Что-то вроде этого:
@TransactionConfiguration(transactionManager = "txManager",defaultRollback = true)
@Transactional
Здесь txManager
- это экземпляр или bean id менеджера транзакций из application context
.
<!-- Transaction Manager -->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
Ответ 8
После опробования множества вышеперечисленных комбинаций у меня сработала следующая настройка с полным откатом после успешного прохождения теста.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:datasource-context-test.xml"})
@TransactionConfiguration(defaultRollback = true)
@Transactional
public class DataAccessTest
{
@Test
public void testSaveRecords()
{ ... }
}