DataSourceUtils 管理参与事务性的JDBC连接


提供一些静态方法用于管理可能参与事务的JDBC连接。JDBCTemplate
或JDBCDaoSupport自动使用它,而且在DataSourceTransactionManager或JTATransactionManager,hibernateTransactionManager中支持。
DataSourceTransactionManager中
DataSourceTransactionManager.DataSourceTransactionObject在事务开始时存储连接,事务完结后使用它获取连接以回复只读,隔离级别及释放连接。在事务挂起和回复时只是解除或重新绑定Holder到当前线程。
成员变量
newConnectionHolder:ConnectionHolder是否为DataSourceTransactionManager doBegin创建。true说明由事务管理器创建,那么在doBegin方法中获取连接并将Holder绑定到线程,在事务完结后由doCleanupAfterCompletion方法接触Holder绑定并释放连接。
mustRestoreAutoCommit:在事务开始时保存连接自动提交模式,进入Spring事务管理将禁用连接自动提交模式,当事务完结后doCleanupAfterCompletion将回复Spring管理之前连接的自动提交模式(无论是禁用的还是启用的:虽然很多数据源提供了自动连接模式,但Spring要求必须禁用)。
方法
hasTransaction 由connectionHolder.isTransactionActive决定,事务开始时设置,完结后清除
setRollbackOnly 设置本地只读标志,AbstractPlatformTransactionManager中提到

/**
* DataSource transaction object, representing a ConnectionHolder.
* Used as transaction object by DataSourceTransactionManager.
*/
private static class DataSourceTransactionObject extends JdbcTransactionObjectSupport {

private boolean newConnectionHolder;

private boolean mustRestoreAutoCommit;

public void setConnectionHolder(ConnectionHolder connectionHolder, boolean newConnectionHolder) {
super.setConnectionHolder(connectionHolder);
this.newConnectionHolder = newConnectionHolder;
}

public boolean isNewConnectionHolder() {
return this.newConnectionHolder;
}

public boolean hasTransaction() {
return (getConnectionHolder() != null && getConnectionHolder().isTransactionActive());
}

public void setMustRestoreAutoCommit(boolean mustRestoreAutoCommit) {
this.mustRestoreAutoCommit = mustRestoreAutoCommit;
}

public boolean isMustRestoreAutoCommit() {
return this.mustRestoreAutoCommit;
}

public void setRollbackOnly() {
getConnectionHolder().setRollbackOnly();
}

public boolean isRollbackOnly() {
return getConnectionHolder().isRollbackOnly();
}
}



DataSourceUtils.ConnectionSynchronization主要用于JTATransactionManager的资源挂起,回复,资源清理;也支持其它应用的资源清理操作。
方法
suspend 事务挂起时调用,除了解绑资源更重要的是尽可能早的释放连接,DataSourceUtils可重新获取新的连接并绑定到Holder
beforeCompletion 事务提交或回滚之前调用,解绑资源和尽可能早的释放连接,当连接被其他应用释放掉DataSourceUtils.releaseConnection(JTA规范规定事务处理完成后,必须关闭所有资源)
afterCompletion 事务提交或回滚之后调用,在JTATransactionManager支持下,对于参与性事务该方法被注册到J2EE事务管理器上由JTA事务完成后执行,有可能与在一个不同于当前线程的线程中执行,那Holder便不可解除。所以我们必须将连接置空。而且在事务完成之后将事务状态:同步只读事务超时引用全部清空。


/**
* Callback for resource cleanup at the end of a non-native JDBC transaction
* (e.g. when participating in a JtaTransactionManager transaction).
* @see org.springframework.transaction.jta.JtaTransactionManager
*/
private static class ConnectionSynchronization extends TransactionSynchronizationAdapter {

private final ConnectionHolder connectionHolder;

private final DataSource dataSource;

private int order;

private boolean holderActive = true;

public ConnectionSynchronization(ConnectionHolder connectionHolder, DataSource dataSource) {
this.connectionHolder = connectionHolder;
this.dataSource = dataSource;
this.order = getConnectionSynchronizationOrder(dataSource);
}

@Override
public int getOrder() {
return this.order;
}

@Override
public void suspend() {
if (this.holderActive) {
TransactionSynchronizationManager.unbindResource(this.dataSource);
if (this.connectionHolder.hasConnection() && !this.connectionHolder.isOpen()) {
// Release Connection on suspend if the application doesn't keep
// a handle to it anymore. We will fetch a fresh Connection if the
// application accesses the ConnectionHolder again after resume,
// assuming that it will participate in the same transaction.
releaseConnection(this.connectionHolder.getConnection(), this.dataSource);
this.connectionHolder.setConnection(null);
}
}
}

@Override
public void resume() {
if (this.holderActive) {
TransactionSynchronizationManager.bindResource(this.dataSource, this.connectionHolder);
}
}

@Override
public void beforeCompletion() {
// Release Connection early if the holder is not open anymore
// (that is, not used by another resource like a Hibernate Session
// that has its own cleanup via transaction synchronization),
// to avoid issues with strict JTA implementations that expect
// the close call before transaction completion.
if (!this.connectionHolder.isOpen()) {
TransactionSynchronizationManager.unbindResource(this.dataSource);
this.holderActive = false;
if (this.connectionHolder.hasConnection()) {
releaseConnection(this.connectionHolder.getConnection(), this.dataSource);
}
}
}

@Override
public void afterCompletion(int status) {
// If we haven't closed the Connection in beforeCompletion,
// close it now. The holder might have been used for other
// cleanup in the meantime, for example by a Hibernate Session.
if (this.holderActive) {
// The thread-bound ConnectionHolder might not be available anymore,
// since afterCompletion might get called from a different thread.
TransactionSynchronizationManager.unbindResourceIfPossible(this.dataSource);
this.holderActive = false;
if (this.connectionHolder.hasConnection()) {
releaseConnection(this.connectionHolder.getConnection(), this.dataSource);
// Reset the ConnectionHolder: It might remain bound to the thread.
this.connectionHolder.setConnection(null);
}
}
this.connectionHolder.reset();
}
}


JTATransactionManager支持下无论事务开始,挂起,回复,完成都与资源操作无关(这是JTA事务具备而本地事务不具备的优点)。在应用中可调用JdbcTemplate或JDBCDaoSupport或DataSourceUtils。在Spring同步激活下,初次调用DataSourceUtils.getConnection时,会注册DataSourceUtils.ConnectionSynchronization实例。hibernateTransactionManager支持下当检测到javax.sql.DataSource时会绑定新的ConnectionHolder,它的connection是由Session提供的因此他只是一个连接代理,没有权利也不必关心连接的释放。只有刚获取的连接才有资格由ConnectionSynchronization资源释放。其它应用与之类似。

方法
doGetConnection获取JDBC连接
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");

ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
//如果Holder被绑定着,并且能使用连接或者Holder作为事务管理器开启事务或Spring同步所管理,这种情况可视为连接可重新获取。
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(dataSource.getConnection());
}
return conHolder.getConnection();
}
// Else we either got no holder or an empty thread-bound holder here.

logger.debug("Fetching JDBC Connection from DataSource");
//获取新的连接
Connection con = dataSource.getConnection();
//spring同步激活了,可用同步实例管理资源
if (TransactionSynchronizationManager.isSynchronizationActive()) {
logger.debug("Registering transaction synchronization for JDBC Connection");
// 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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值