我的DAO中的以下代码完全正常。
public void insert(final Person person) {
transactionTemplate.execute(new TransactionCallback<Void>() {
public Void doInTransaction(TransactionStatus txStatus) {
try {
getJdbcTemplate().execute("insert into person(username, password) values ('" + person.getUsername() + "','" + person.getPassword() + "')");
} catch (RuntimeException e) {
txStatus.setRollbackOnly();
throw e;
}
return null;
}
});
}
以下是我的春季配置。
<bean id="derbyds" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="username" value="app" />
<property name="password" value="app" />
<property name="url" value="jdbc:derby:mytempdb" />
</bean>
<bean id="persondaojdbc" class="com.napp.dao.impl.PersonDaoJdbcImpl">
<property name="dataSource" ref="derbyds" />
<property name="transactionTemplate">
<bean class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="derbyds"/>
</bean>
我想知道的是
<bean id="persondaojdbc" class="com.napp.dao.impl.PersonDaoJdbcImpl">
<property name="dataSource" ref="derbyds" />
<property name="transactionTemplate">
<bean class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="derbyds"/>
</bean>
现在,它必须要求TransactionManager和代码(在我的情况下是jdbc模板)在同一个连接上运行。我假设它们都从DataSource获取Connection对象。 DataSource池连接,当你多次调用getConnection时,它会有机会获得不同的Connection对象。 spring如何确保TransactionManager和JdbcTemplate最终获得相同的连接对象。我的理解是,如果没有发生这种情况,回滚或提交将不起作用,对吗?有人可以对此更加清楚。
答案 0 :(得分:2)
如果您查看JdbcTemplate
的代码(其中一种execute(...)
方法),您会看到
Connection con = DataSourceUtils.getConnection(getDataSource());
尝试从Connection
注册的ConnectionHolder
检索TransactionSynchronizationManager
。
如果没有这样的对象,它只是从DataSource
获得连接并注册它(如果它在事务环境中,即你有一个事务管理器)。否则,它会立即返回已注册的对象。
这是代码(剥离日志和东西)
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
conHolder.setConnection(dataSource.getConnection());
}
return conHolder.getConnection();
}
// Else we either got no holder or an empty thread-bound holder here.
Connection con = dataSource.getConnection();
// flag set by the TransactionManager
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// Use same Connection for further JDBC actions within the transaction.
// Thread-bound object will get removed by synchronization at transaction completion.
ConnectionHolder holderToUse = conHolder;
if (holderToUse == null) {
holderToUse = new ConnectionHolder(con);
}
else {
holderToUse.setConnection(con);
}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(
new ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
}
}
return con;
您会注意到JdbcTemplate
尝试
finally {
DataSourceUtils.releaseConnection(con, getDataSource());
}
释放Connection,但只有在非事务性环境中才会发生这种情况,即。
如果它不是外部管理的(也就是说,没有绑定到线程)。
因此,在事务性世界中,JdbcTemplate
将重用相同的Connection
对象。