引用:由于JdbcTemplate、NamedParameterJdbcTemplate、SimpleJdbcTemplate类使用DataSourceUtils获取及释放连接,而且连接是与线程绑定的,因此这些JDBC模板类是线程安全的,即JdbcTemplate对象可以在多线程中重用。
spring的JDBC:
DataSourceUtils得到一个数据库连接的实现,和hibernate等ORM框架一样,得到连接后放入ThreadLocal中,同一个线程用同一个连接,源码如下:
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;
}
其中,获取到一个数据库连接后,放入一个事务中并放入ThreadLocal,源码如下:
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<Set<TransactionSynchronization>>("Transaction synchronizations");
//...
public static void registerSynchronization(TransactionSynchronization synchronization)
throws IllegalStateException {
Assert.notNull(synchronization, "TransactionSynchronization must not be null");
if (!isSynchronizationActive()) {
throw new IllegalStateException("Transaction synchronization is not active");
}
synchronizations.get().add(synchronization);
}
MyBites:
1)我们在配置文件中,一般这么配置,但是只是获取读取解析配置session工厂的一个bean,该bean其中一个属性为SqlSessionFactory sqlSessionFactory;即session工厂,通过该对象可获得一个数据库连接:
配置文件:
<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 ,自动扫描加载Sql映射文件/接口-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:mapping/*.xml"></property>
</bean>
在mybatis中,session工厂的默认实现为DefaultSqlSessionFactory类:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
2)其中,获取数据库连接,仍然是用底层rt.jar的DataSource,具体要看配置的事务类型TransactionFactory,比如下面这种,就是使用spring本身的,即DataSourceUtils的。
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
mybatis中,可以使用三种处理事务类型,如下图,前两种是mybatis本身封装的,使用原生的rt.jar中DataSource获取数据库连接。
3)session中的Executor executor,也有三种实现(BatchExecutor批量执行、ClosedExecutor、ReuseExecutor、SimpleExecutor),如下图,但都会继承BaseExecutor这个基本类,具体属性之后再看,待续.......