- 浏览: 50846 次
- 性别:
- 来自: 南京
文章分类
最新评论
事务由spring管理,可以理解为由spring管理数据库连接。ibatis执行sql时,需保证获取的数据库连接与spring管理的数据库连接是同一个
这篇文章主要从ibatis的角度分析,ibatis如何获取spring中管理的数据库连接(这里最主要的是用到了ThreadLocal技术)
应用配置:
程序调用(以insert为例):
spring-orm#sqlMapClientTemplate#insert
spring-orm#sqlMapClientTemplate#execute
关键点:
SqlMapClientFactoryBean#afterPropertiesSet
设置DataSource类型属性时,会为其生成代理类。该代理类并不是通过spring aop实现的代理类,只是实现了DataSource接口的静态代理类。
ibatis通过代理的DataSource的getConnection获取数据库连接
TransactionAwareDataSourceProxy是连接ibatis与spring的关键。ibatis获取数据库连接都是通过这个spring-jdbc中的类
TransactionAwareDataSourceProxy#getConnection
TransactionAwareDataSourceProxy#getTransactionAwareConnectionProxy
spring对TransactionAwareDataSourceProxy获取的数据库连接也进行了代理,生成代理类的方式为Proxy+InvocationHandler
TransactionAwareInvocationHandler#invoke
这里横切面主要为我们做的主要是获取同步的连接(线程内的)
DataSourceUtils#doGetConnection
上面分析这些,ibatis本质上还是让TransactionSynchronizationManager获取数据库连接。至于中间的过程的实现,见仁见智
TransactionSynchronizationManager类中利用threadLocal技术保证了一个线程获取的数据库连接是一样的
这篇文章主要从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技术保证了一个线程获取的数据库连接是一样的
发表评论
-
spring疑难解惑-循环依赖的解决
2020-06-17 23:27 554AbstractAutowireCapableBeanFact ... -
spring容器
2019-07-14 08:47 308private final ServletContainer ... -
spring容器
2019-07-13 23:35 0spring容器与springmvc容器 73 ... -
spring源码学习系列2.6-spring ioc原理-codes
2019-03-05 22:56 491web.xml <listener> < ... -
spring源码学习系列3.4-spring mvc原理-codes
2019-01-21 22:46 302本篇章从核心类角度解读springmvc的原理 web.xm ... -
spring源码学习系列4.2-spring aop原理-codes
2018-12-04 22:29 566jdk: Proxy InvocationHandler ... -
spring源码学习系列4-3种常用的自动代理创建器
2018-09-02 15:48 5773种自动代理器是 AnnotationAwareAspectJ ... -
spring源码学习系列1.2-spring事务代理深入分析2
2018-05-27 19:46 457提示: BeanPostProcessor AopUtils ... -
spring源码学习系列2.5-ApplicationContext初始化-设计模式
2018-05-08 15:17 528ApplicationContext容器的初始化可以通过模板方 ... -
spring源码学习系列3.3-DispatcherServlet初始化-设计模式
2018-05-07 11:12 630springmvc的核心是DispatcherServlet ... -
封装spring-security
2018-01-23 19:33 523github地址: https://github.com/ne ... -
eclipse导入spring源码
2018-05-12 07:20 986spring在git上的项目时gradle管理jar包的,所以 ... -
spring源码学习系列3.2.3-异常页面拦截机制
2017-07-29 19:07 777前序:本文的意义在于了解 tomcat处理异常 请求访问 ... -
spring源码学习系列3.2.2-How to bind String to Date
2017-07-17 12:40 604springmvc开发中,经常需将界面日期数据(String) ... -
spring源码学习系列3.2.1-command对象的绑定
2017-05-28 12:00 994在<spring源码学习系列3.2-handlerAda ... -
spring源码学习系列3.2-handlerAdapter执行
2017-05-28 12:01 414DispatcherServlet#doDispatch中调用 ... -
spring源码学习系列3.1-handlerMapping初始化
2017-05-28 11:56 706SimpleUrlHandlerMapping的继承体系 or ... -
spring源码学习系列2.4-finishRefresh会做什么
2017-05-06 16:36 584spring容器初始化完成后,调用finishRresh 该 ... -
spring源码学习系列3-springmvc原理
2017-05-28 11:56 461问题: springmvc是如何控 ... -
spring源码学习系列2-容器初始化入口-refresh
2017-04-23 21:33 480context=XmlWebApplicationContex ...
相关推荐
Spring 4.1 引入了对Java 8的支持,包括日期时间API,改进了Groovy bean定义,增强了数据源配置,以及提升了整体性能和稳定性。 3. **MyBatis** MyBatis 是一个持久层框架,它允许开发者编写SQL语句并与Java对象...
MyBatis-Spring也支持容器管理的事务,这意味着可以通过Spring的声明式事务管理功能来管理MyBatis的操作。可以使用@Transactional注解,也可以在XML配置文件中配置事务属性。 5. 使用SqlSession 5.1 ...
1. **声明式事务管理**:通过在Spring配置文件中定义@Transactional注解,实现对事务的管理。 2. **编程式事务管理**:对于复杂的业务逻辑,可以使用编程式事务管理,即通过TransactionTemplate类来手动控制事务的...
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...
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.6.1. @Transactional 有关的设置 ...
MyBatis-Spring提供了多种事务管理策略,包括标准配置、容器管理事务和编程式事务管理。 ##### 4.1 标准配置 在标准配置下,MyBatis-Spring利用Spring的PlatformTransactionManager自动管理事务边界。这种模式适用...
### Spring与iBATIS集成应用详解...通过本文的介绍,您可以了解到如何在Spring框架中使用iBATIS来构建高效可靠的数据库访问层,并掌握相关的事务处理、异常管理和测试技巧。希望本文能够为您的项目开发提供有用的指导。
创建`StudentDaoSqlMap`类,实现对`Student`实体的操作: ```java package cn.hsw.dao; import org.springframework.orm.ibatis.SqlMapClientTemplate; import cn.hsw.model.Student; public class ...
随着 Spring 3.0 的发布,它仅支持 iBatis 2.x 版本,而 MyBatis 社区希望能够在 Spring 3.0 中加入对 MyBatis 3 的支持。然而,在 MyBatis 3 正式发布之前,Spring 3.0 的开发已经结束。由于 Spring 开发团队不愿...
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. ...
在JpetStore 4.0中,Spring主要应用于业务层的改造,通过AOP提供事务管理,使用Beanfactory分离接口与实现,增强了灵活性。此外,Spring的ORM支持与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 - **其他...
4.1节介绍资源基础知识,4.2节探讨Spring内置的Resource实现,4.3节介绍如何访问这些资源,4.4节讲解Resource通配符路径的使用。 【第五章】Spring表达式语言(SpEL)是一个强大的表达式语言,支持在运行时查询和...
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. ...
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...
2.1 更强的事务管理:Spring 2.0增强了对声明式事务的支持,使得事务管理更为简便,且支持多种事务管理策略,如JTA和DataSourceTransactionManager。 2.2 数据访问集成:Spring 2.0加强了与各种持久层技术的集成,...
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...
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 定义事务参数 ...
书的最后给出了一个设计优雅、层次清晰的示例程序JGameStore,该示例涵盖全书的大部分知识点,可以作为iBATIS学习和Web开发的经典案例,非常值得深入研究。 本书既可为广大的开发人员(不仅仅是Web应用程序开发人员)...
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代理事务 ...