`

spring源码学习系列4.1-spring实现对ibatis的事务管理

阅读更多
事务由spring管理,可以理解为由spring管理数据库连接。ibatis执行sql时,需保证获取的数据库连接与spring管理的数据库连接是同一个

这篇文章主要从ibatis的角度分析,ibatis如何获取spring中管理的数据库连接(这里最主要的是用到了ThreadLocal技术)


应用配置:
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation">
			<value>classpath:context/dao/SqlMapConfig.xml</value>
		</property>
	</bean>

	<bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
		<property name="sqlMapClient" ref="sqlMapClient"></property>
	</bean>

	<bean id="userDAO" class="com.byron.template.dao.impl.UserDAOImpl">
		<property name="sqlMapClientTemplate" ref="sqlMapClientTemplate"></property>
	</bean>



程序调用(以insert为例):
public class UserDAOImpl extends SqlMapClientDaoSupport implements UserDAO {  

  
    public int insertUser(User user) {  
        int id = (Integer) getSqlMapClientTemplate().insert("insertUser", user);  
        return id;  
    }  
}



spring-orm#sqlMapClientTemplate#insert
public Object insert(final String statementName, final Object parameterObject)
			throws DataAccessException {

		return execute(new SqlMapClientCallback<Object>() {
			public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
				return executor.insert(statementName, parameterObject);
			}
		});
	}



spring-orm#sqlMapClientTemplate#execute
public <T> T execute(SqlMapClientCallback<T> action) throws DataAccessException {
		Assert.notNull(action, "Callback object must not be null");
		Assert.notNull(this.sqlMapClient, "No SqlMapClient specified");

		SqlMapSession session = this.sqlMapClient.openSession();
		if (logger.isDebugEnabled()) {
			logger.debug("Opened SqlMapSession [" + session + "] for iBATIS operation");
		}
		Connection ibatisCon = null;

		try {
			Connection springCon = null;
			DataSource dataSource = getDataSource();
			boolean transactionAware = (dataSource instanceof TransactionAwareDataSourceProxy);

			// Obtain JDBC Connection to operate on...
			try {
				ibatisCon = session.getCurrentConnection();
				if (ibatisCon == null) {
					springCon = (transactionAware ?
							dataSource.getConnection() : DataSourceUtils.doGetConnection(dataSource));
					session.setUserConnection(springCon);
					if (logger.isDebugEnabled()) {
						logger.debug("Obtained JDBC Connection [" + springCon + "] for iBATIS operation");
					}
				}
				else {
					if (logger.isDebugEnabled()) {
						logger.debug("Reusing JDBC Connection [" + ibatisCon + "] for iBATIS operation");
					}
				}
			}
			catch (SQLException ex) {
				throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
			}

			// Execute given callback...
			try {
				return action.doInSqlMapClient(session);
			}
			catch (SQLException ex) {
				throw getExceptionTranslator().translate("SqlMapClient operation", null, ex);
			}
			finally {
				try {
					if (springCon != null) {
						if (transactionAware) {
							springCon.close();
						}
						else {
							DataSourceUtils.doReleaseConnection(springCon, dataSource);
						}
					}
				}
				catch (Throwable ex) {
					logger.debug("Could not close JDBC Connection", ex);
				}
			}

			// Processing finished - potentially session still to be closed.
		}
		finally {
			// Only close SqlMapSession if we know we've actually opened it
			// at the present level.
			if (ibatisCon == null) {
				session.close();
			}
		}
	}





关键点:
springCon = (transactionAware ?  
                            dataSource.getConnection() : DataSourceUtils.doGetConnection(dataSource));





SqlMapClientFactoryBean#afterPropertiesSet
public void afterPropertiesSet() throws Exception {
		if (this.lobHandler != null) {
			// Make given LobHandler available for SqlMapClient configuration.
			// Do early because because mapping resource might refer to custom types.
			configTimeLobHandlerHolder.set(this.lobHandler);
		}

		try {
			this.sqlMapClient = buildSqlMapClient(this.configLocations, this.mappingLocations, this.sqlMapClientProperties);

			// Tell the SqlMapClient to use the given DataSource, if any.
			if (this.dataSource != null) {
				TransactionConfig transactionConfig = (TransactionConfig) this.transactionConfigClass.newInstance();
				DataSource dataSourceToUse = this.dataSource;
				if (this.useTransactionAwareDataSource && !(this.dataSource instanceof TransactionAwareDataSourceProxy)) {
					dataSourceToUse = new TransactionAwareDataSourceProxy(this.dataSource);
				}
				transactionConfig.setDataSource(dataSourceToUse);
				transactionConfig.initialize(this.transactionConfigProperties);
				applyTransactionConfig(this.sqlMapClient, transactionConfig);
			}
		}

		finally {
			if (this.lobHandler != null) {
				// Reset LobHandler holder.
				configTimeLobHandlerHolder.remove();
			}
		}
	}


设置DataSource类型属性时,会为其生成代理类。该代理类并不是通过spring aop实现的代理类,只是实现了DataSource接口的静态代理类。

ibatis通过代理的DataSource的getConnection获取数据库连接


TransactionAwareDataSourceProxy是连接ibatis与spring的关键。ibatis获取数据库连接都是通过这个spring-jdbc中的类

TransactionAwareDataSourceProxy#getConnection
@Override
	public Connection getConnection() throws SQLException {
		DataSource ds = getTargetDataSource();
		Assert.state(ds != null, "'targetDataSource' is required");
		return getTransactionAwareConnectionProxy(ds);
	}


TransactionAwareDataSourceProxy#getTransactionAwareConnectionProxy
protected Connection getTransactionAwareConnectionProxy(DataSource targetDataSource) {
		return (Connection) Proxy.newProxyInstance(
				ConnectionProxy.class.getClassLoader(),
				new Class[] {ConnectionProxy.class},
				new TransactionAwareInvocationHandler(targetDataSource));
	}



spring对TransactionAwareDataSourceProxy获取的数据库连接也进行了代理,生成代理类的方式为Proxy+InvocationHandler

TransactionAwareInvocationHandler#invoke
if (this.target == null) {
				if (this.closed) {
					throw new SQLException("Connection handle already closed");
				}
				if (shouldObtainFixedConnection(this.targetDataSource)) {
					this.target = DataSourceUtils.doGetConnection(this.targetDataSource);
				}
			}
			Connection actualTarget = this.target;
			if (actualTarget == null) {
				actualTarget = DataSourceUtils.doGetConnection(this.targetDataSource);
			}


这里横切面主要为我们做的主要是获取同步的连接(线程内的)
DataSourceUtils#doGetConnection

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())) {
			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();

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


上面分析这些,ibatis本质上还是让TransactionSynchronizationManager获取数据库连接。至于中间的过程的实现,见仁见智

TransactionSynchronizationManager类中利用threadLocal技术保证了一个线程获取的数据库连接是一样的
分享到:
评论

相关推荐

    springmvc4.1+spring4.1+mybatis3.2+spring-security3.2 jar包

    Spring 4.1 引入了对Java 8的支持,包括日期时间API,改进了Groovy bean定义,增强了数据源配置,以及提升了整体性能和稳定性。 3. **MyBatis** MyBatis 是一个持久层框架,它允许开发者编写SQL语句并与Java对象...

    mybatis-spring-1.0.0-RC3-reference

    MyBatis-Spring也支持容器管理的事务,这意味着可以通过Spring的声明式事务管理功能来管理MyBatis的操作。可以使用@Transactional注解,也可以在XML配置文件中配置事务属性。 5. 使用SqlSession 5.1 ...

    Spring iBatis Learning Notes

    1. **声明式事务管理**:通过在Spring配置文件中定义@Transactional注解,实现对事务的管理。 2. **编程式事务管理**:对于复杂的业务逻辑,可以使用编程式事务管理,即通过TransactionTemplate类来手动控制事务的...

    javaweb项目常用jar包

    ibatis-2.3.4.726.jar jackson-all-1.7.4.jar jackson-annotation-2.3.0.jar jackson-core-2.3.3.jar jackson-databind-2.3.3.jar java_websocket.jar javassist-3.11.0.GA.jar jaxen-1.1.jar jboss-logging...

    Spring-Reference_zh_CN(Spring中文参考手册)

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.6.1. @Transactional 有关的设置 ...

    mybatis-spring-1.0.2-reference.pdf

    MyBatis-Spring提供了多种事务管理策略,包括标准配置、容器管理事务和编程式事务管理。 ##### 4.1 标准配置 在标准配置下,MyBatis-Spring利用Spring的PlatformTransactionManager自动管理事务边界。这种模式适用...

    Spring and iBATIS

    ### Spring与iBATIS集成应用详解...通过本文的介绍,您可以了解到如何在Spring框架中使用iBATIS来构建高效可靠的数据库访问层,并掌握相关的事务处理、异常管理和测试技巧。希望本文能够为您的项目开发提供有用的指导。

    ibatis+spring完全整合

    创建`StudentDaoSqlMap`类,实现对`Student`实体的操作: ```java package cn.hsw.dao; import org.springframework.orm.ibatis.SqlMapClientTemplate; import cn.hsw.model.Student; public class ...

    spring chm文档

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. ...

    基于struts+spring+ibatis的J2EE开发

    在JpetStore 4.0中,Spring主要应用于业务层的改造,通过AOP提供事务管理,使用Beanfactory分离接口与实现,增强了灵活性。此外,Spring的ORM支持与Ibatis的结合,使得数据访问更加灵活和高效。 Ibatis是一个不同于...

    ibatis 一个简单的项目详解

    - **ibatis核心库**:ibatis-2.3.0.677.jar - **Spring框架**:spring.jar - **Struts2核心及插件**:struts2-core-2.0.11.2.jar、struts2-spring-plugin-2.0.11.2.jar - **XWork核心库**:xwork-2.0.5.jar - **其他...

    跟我学spring

    4.1节介绍资源基础知识,4.2节探讨Spring内置的Resource实现,4.3节介绍如何访问这些资源,4.4节讲解Resource通配符路径的使用。 【第五章】Spring表达式语言(SpEL)是一个强大的表达式语言,支持在运行时查询和...

    Spring 2.0 开发参考手册

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. ...

    Spring中文帮助文档

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...

    Spring 2.0 中文用户指南.pdf

    2.1 更强的事务管理:Spring 2.0增强了对声明式事务的支持,使得事务管理更为简便,且支持多种事务管理策略,如JTA和DataSourceTransactionManager。 2.2 数据访问集成:Spring 2.0加强了与各种持久层技术的集成,...

    Spring API

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...

    Spring in Action(第二版 中文高清版).part2

    6.1.2 理解Spring对事务管理的支持 6.2 选择事务管理器 6.2.1 JDBC事务 6.2.2 Hibernate事务 6.2.3 JPA事务 6.2.4 JDO事务 6.2.5 JTA事务 6.3 在Spring中编写事务 6.4 声明式事务 6.4.1 定义事务参数 ...

    iBATIS实战

    书的最后给出了一个设计优雅、层次清晰的示例程序JGameStore,该示例涵盖全书的大部分知识点,可以作为iBATIS学习和Web开发的经典案例,非常值得深入研究。 本书既可为广大的开发人员(不仅仅是Web应用程序开发人员)...

    Spring in Action(第2版)中文版

    6.1.2理解spring对事务管理的支持 6.2选择事务管理器 6.2.1jdbc事务 6.2.2hibernate事务 6.2.3jpa事务 6.2.4jdo事务 6.2.5jta事务 6.3在spring中编写事务 6.4声明式事务 6.4.1定义事务参数 6.4.2代理事务 ...

Global site tag (gtag.js) - Google Analytics