對於插入兩個不同表中的DAO方法,我有一個彈簧單元測試。測試完成後,其中一個插入按預期回滾,但不是另一個!我真的無法弄清楚發生了什麼。我已經多次調試了這個測試,以便我可以看到數據庫中何時出現(未提交)更改,但只有一個消失。在Spring單元測試中未回滾的Vanilla JDBC更新
我能看到的唯一區別是在一種情況下插入是用原始JDBC完成的,而在第二種情況下用Sping的JdbcTemplate完成。但是,不應該都在同一個交易中,然後回滾?
這裏是我的測試類:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/test-context.xml"})
@Rollback
@Transactional(transactionManager = "txManager")
public class MyDaoIntegrationTest {
@Autowired
private DataSource dataSource;
@Autowired
private MyDao myDao;
@Test
public void createMyObject_test() throws Exception {
MyObject myObject = new MyObject();
myDao.createMyObject(myObject, 123L);
}
}
我測試context.xml文件看起來是這樣的:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="myDao" class="my.package.myDao">
<constructor-arg name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="url" value="${unit.test.db.url}"/>
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="username" value="${unit.test.db.user}"/>
<property name="password" value="${unit.test.db.pass}"/>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
進行測試看起來大致(取消了關閉連接等噪聲)的方法,以便:
public void createMyObject(MyObject vo, long refId) throws SQLException {
Connection cn = dataSource.getConnection();
PreparedStatement ps = cn.prepareStatement("insert into MY_OBJECT (COL1, COL, ...)) values (?,?,...)");
ps.setInt(1, vo.getCol1());
ps.setInt(2, vo.getCol2());
...
ps.executeUpdate();
MyObjectEventVO event = new MyObjectEventVO();
createMyObjectEvent(event);
}
public void createMyObjectEvent(MyObjectEventVO vo) throws DataAccessException {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String updateSql =
"insert into MY_OBJECT_EVENT(COL1, COL2, ...) "
+ "values (?, ?, ...)";
Object[] params = {vo.getCol1(), vo.getCol2(), ... };
int[] types = {Types.INTEGER, Types.VARCHAR, ...};
jdbcTemplate.update(updateSql, params, types);
}
更新 我試過註釋掉createMyObjectEvent(event)的調用,以便只發生一次插入。最終結果是相同的:第一個插入不回滾。所以第一次插入的交易似乎有問題。
更新2 我重構了第一次插入也使用JdbcTemplate,然後一切工作正常!所以這個問題可以重新表述爲:如何讓vanilla JDBC代碼在春季單元測試中回滾?
是否有可能createMyObjectEvent有一個自己的事務?例如。這是myDao註釋嗎? –
MyDao上沒有註釋。單元測試之外的所有配置都來自XML。 – inovaovao
爲什麼在第二種方法中使用新的JdbcTemplate? – Nemesis