事务模板和事务管理器连接对象

3
我的 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;
        }
    });
}

以下是我的Spring配置。
<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>

What i wanted to know is how does the

<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>

现在,事务管理器和代码(在我这里是JDBC模板)必须操作相同的连接。我假设它们都从数据源获取连接对象。数据源池化连接,在多次调用getConnection时有可能会获得不同的连接对象。Spring是如何确保TransactionManager和JdbcTemplate最终获取相同的连接对象的呢?我的理解是,如果没有发生这种情况,回滚或提交将无法正常工作,对吗?能否有人更详细地解释一下这个问题。
1个回答

3

如果您查看JdbcTemplate的代码(其中一个execute(...)方法),您会发现

Connection con = DataSourceUtils.getConnection(getDataSource());

这段代码试图从已经在TransactionSynchronizationManager注册的ConnectionHolder中检索Connection

如果没有这样的对象,则只需从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());
}

释放连接,但仅适用于非事务环境,即如果未在外部管理(即未绑定到线程),则会发生这种情况。因此,在事务世界中,JdbcTemplate将重复使用同一Connection对象。

这是否意味着如果我直接在doInTransaction中使用JDBC代码可能会有问题?因为如果我们在doInTransaction中创建Connection对象,它肯定不会是与TransactionManager中的那个Connection对象相同的。 - noi.m
没错。如果直接使用JDBC,你将失去@Transactional的行为,除非你做类似于JdbcTemplate所做的事情,即使用DataSourceUtilsTransactionSynchronizationManager - Sotirios Delimanolis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接