1. 从SqlSessionDaoSupport开始

通常我们使用MyBatis会让自己的DAO继承SqlSessionDaoSupport,那么SqlSessionDaoSupport是如何运作的呢,下面是SqlSessionDaoSupport的源代码

/*
* Copyright 2010 The myBatis Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mybatis.spring.support; import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.support.DaoSupport;
import org.springframework.util.Assert; /**
* Convenient super class for MyBatis SqlSession data access objects.
* It gives you access to the template which can then be used to execute SQL methods.
* <p>
* This class needs a SqlSessionTemplate or a SqlSessionFactory.
* If both are set the SqlSessionFactory will be ignored.
*
* @see #setSqlSessionFactory
* @see #setSqlSessionTemplate
* @see SqlSessionTemplate
* @version $Id: SqlSessionDaoSupport.java 3266 2010-11-22 06:56:51Z simone.tripodi $
*/
public abstract class SqlSessionDaoSupport extends DaoSupport { // 这个SqlSession就是我们平时用来执行SQL和事务的一次会话
private SqlSession sqlSession; private boolean externalSqlSession; // 可以看到以下两个Autowired的set方法,实际上他们的功能都是设置sqlSession的实例
// 区别在于一个是通过传入sqlSessionFactory然后包装成SqlSessionTemplate
// 另一个直接传入SqlSessionTemplate赋值给sqlSession
@Autowired(required = false)
public final void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
} @Autowired(required = false)
public final void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSession = sqlSessionTemplate;
this.externalSqlSession = true;
} /**
* Users should use this method to get a SqlSession to call its statement methods
* This is SqlSession is managed by spring. Users should not commit/rollback/close it
* because it will be automatically done.
*
* @return Spring managed thread safe SqlSession
*/
public final SqlSession getSqlSession() {
return this.sqlSession;
} /**
* {@inheritDoc}
*/
protected void checkDaoConfig() {
Assert.notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
} }

2.SqlSessionDaoSupport中的SqlSession产生

先提一提既然我们是用dao去继承这个SqlSessionDaoSupport,观察我们的dao的配置

    <bean id="userDao" class="dao.UserDao">
<!--<property name="sqlSessionFactory" ref="sqlSessionFactory" />-->
<property name="sqlSessionTemplate" ref="sqlSession" />
</bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" >
<!-- 第一个参数是 sqlSessionFactory -->
<constructor-arg index="0" ref="sqlSessionFactory"/>
<!-- 第二个参数是 ExecutorType -->
<constructor-arg index="1" ref="BATCH"/>
</bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 指定MyBatis配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml" />
<!-- 导入Mapper -->
<property name="mapperLocations" value="classpath*:mappers/*.xml" />
</bean> <!-- datasource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatistest?characterEncoding=utf8" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>

观察我们的dao的配置可以发现我们可以配置sqlSessionFactory和sqlSessionTemplate,实际上我们配置 sqlSessionTemplate的话就是能多配置一个ExecutorType参数(这个参数在MyBatis的Settings参数里也可以找 到,叫做defaultExecutorType,参数配置详细介绍见 http://mybatis.github.io/mybatis-3/configuration.html),这个参数的选项有三个:

SIMPLE: 普通SQL执行器,不会使用预解析和批量处理

REUSE: 重用prepared statement

BATCH: 不但重用prepared statement,而且能执行批量处理,如

public void insertUsers(User[] users) {
for (User user : users) {
sqlSession.insert("org.mybatis.spring.sample.mapper.UserMapper.insertUser", user);
}
}

3. 分析sqlSessionTemplate的构造

查看sqlSessionTemplate的源代码,关键部分如下

    /**
* Constructs a Spring managed {@link SqlSession} with the given
* {@link SqlSessionFactory} and {@link ExecutorType}.
* A custom {@link SQLExceptionTranslator} can be provided as an
* argument so any {@link PersistenceException} thrown by MyBatis
* can be custom translated to a {@link RuntimeException}
* The {@link SQLExceptionTranslator} can also be null and thus no
* exception translation will be done and MyBatis exceptions will be
* thrown
*
* @param sqlSessionFactory
* @param executorType
* @param exceptionTranslator
*/
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) { Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
Assert.notNull(executorType, "Property 'executorType' is required"); this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
}

它的功能如下

1) 设置sqlSessionFactory,查看上面的xml的配置,就知道sqlSessionFactory这个东西其实就是用来指定 datasource,读取mybatis配置(environment,settings种种),还有读取mybatis的各个sql语句的 mapper的东西

2) 设置executor type,上面已经介绍过了

3) 设置exception translator,这个东西是用来将jdbc的异常转换成spring的sql异常的东西(因为jdbc的异常很单一,无法详细的表达出错时错误到底 是什么,所以spring自己写了一套更好理解的异常,这是题外话),这个东西保持默认就可以了,所以我们在配置sqlSessionTemplate的 bean的时候并没有配置这个参数,如果没有配置,则构造方法会使用一个默认的(这是一个重载方法,另外还有一个构造方法是不需要设置这个参数的,那个构 造方法调用了这个构造方法,其中execeptionTranslator就是传了一个默认的进来)

4) 对SqlSessionInteceptor()设置了一个代理,从这个动态代理的构造函数参数我们就能看出来这个东西是一个SqlSession

其中,这个SqlSessionInterceptor是SqlSessionTemplate一个内部类,他返回了一个SqlSession关键代码如下

            final SqlSession sqlSession = SqlSessionUtils.getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType);

很简单,其实就是用sqlSessionFactory和executorType生成了一个sqlSession

接下来进入一段七弯八拐的调用,过程如下

SqlSessionUtils.getSqlSession() -> SessionFactory.openSession(executorType, conn) -> DefaultSessionFactory.openSession(ExecutorType execType) ->Configuration.newExecutor(tx, execType, autoCommit) -> return new DefaultSqlSession(configuration, executor)
其中的关键部分是newExecutor(),这玩意就是生成SQL语句执行器的地方,生成的代码如下:
  public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
// 这里就是根据ExecutorType创建Executor的地方
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
// 这句就是判断setting里的cacheEnabled参数的地方
// 所以设置了cacheEnabled参数后就会被包装成缓存Executor
if (cacheEnabled) {
executor = new CachingExecutor(executor, autoCommit);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
主要做的事情就是 1) 根据executorType生成合适的executor 2) 更具cacheEnabled参数包装executor 

至此, SqlSessionTemplate中的sqlSessionProxy的executor终于生成出来,以后我们使用dao中的session来执行sql相关的操作用的就都是这个SqlSessionTemplate中的sqlSessionProxy

最后,画个图总结一下


也就是说,我们其实使用的是SqlSessionTemplate在做各种数据库操作,这个东西读取了我们的datasource和mybatisconfig,用它的Executor去执行我们Mapper里的sql语句来获取查询结果

MyBatis-Spring 执行SQL语句的流程的更多相关文章

  1. MyBatis直接执行sql语句mapper

    <select id="queryBySql" resultType="HashMap"> <![CDATA[ ${sql} ]]> & ...

  2. 在mybatis执行SQL语句之前进行拦击处理

    转载自:http://blog.csdn.net/hfmbook/article/details/41985853 比较适用于在分页时候进行拦截.对分页的SQL语句通过封装处理,处理成不同的分页sql ...

  3. 在mybatis中写sql语句的一些体会

    本文会使用一个案例,就mybatis的一些基础语法进行讲解.案例中使用到的数据库表和对象如下: article表:这个表存放的是文章的基础信息 -- ------------------------- ...

  4. Mybatis如何执行Select语句,你真的知道吗?

    持续原创输出,点击上方蓝字关注我吧 作者:不才陈某 博客:https://chenjiabing666.github.io 前言 本篇文章是Myabtis源码分析的第三篇,前两篇分别介绍了Mybati ...

  5. 10.1(java学习笔记)JDBC基本操作(连接,执行SQL语句,获取结果集)

    一.JDBC JDBC的全称是java database connection java数据库连接. 在java中需要对数据库进行一系列的操作,这时就需要使用JDBC. sun公司制定了关于数据库操作 ...

  6. 4.5 .net core下直接执行SQL语句并生成DataTable

    .net core可以执行SQL语句,但是只能生成强类型的返回结果.例如var blogs = context.Blogs.FromSql("SELECT * FROM dbo.Blogs& ...

  7. [转]在EntityFramework6中执行SQL语句

    本文转自:http://www.cnblogs.com/wujingtao/p/5412329.html 在上一节中我介绍了如何使用EF6对数据库实现CRDU以及事务,我们没有写一句SQL就完成了所有 ...

  8. 在EntityFramework6中执行SQL语句

    在EntityFramework6中执行SQL语句 在上一节中我介绍了如何使用EF6对数据库实现CRDU以及事务,我们没有写一句SQL就完成了所有操作.这一节我来介绍一下如何使用在EF6中执行SQL语 ...

  9. 详解Java的MyBatis框架中SQL语句映射部分的编写

    这篇文章主要介绍了Java的MyBatis框架中SQL语句映射部分的编写,文中分为resultMap和增删查改实现两个部分来讲解,需要的朋友可以参考下 1.resultMap SQL 映射XML 文件 ...

随机推荐

  1. nodejs7.0 试用 async await

    nodejs 7.0.0 已经支持使用 --harmony-async-await 选项来开启async 和 await功能. 在我看来,yield 和 async-await 都是在特定范围内实现了 ...

  2. GISer 应届生找工作历程(完结)

    有半个月没更博客了,前几天在学校准备这保研,因为没有时间复习高数自然就没有过.    也没啥的,我本来就不打算复习,就是看看运气咋样(哈哈).在昨天开始跑的招聘会,一天下来不同地方跑了三家挺累的,记录 ...

  3. ALI OSS RequestTimeTooSkewed

    php版阿里oss sdk,请求时抛RequestTimeTooSkewed错误,说时间差距太大,搜了一下发现是服务器的时间设置问题. 我们在安装完Centos Linux操作系统之后,点击系统的时间 ...

  4. OpenCV3读取、写入和保存图像

    需要说明的是在OpenCV3中已经将imread()和imwrite()函数转移到imgcodecs模块中,因此读写图像时,需要包含imgcodecs.hpp头文件,但是highgui.hpp头文件中 ...

  5. java线程安全和线程同步

    第一部分 线程安全(1)——变量安全 http://blog.csdn.net/cuiran/article/details/6150357 第二部分 线程安全(2)——ThreadLocal变量 h ...

  6. C#如何获取快捷方式指向的目标文件

    前几天,做个小程序时遇到的问题,在百度上搜索了很久,没有发现好的解决方案,在英文网站上立刻搜到办法,看来还是国外的资源要全面一些,只是Google经常访问不正常,没办法啊. “C#如何获取快捷方式指向 ...

  7. CentOS6.5下 yum安装LAMP

    CentOS下yum安装LAMP   1. 用yum安装Apache,Mysql,PHP. 1.1安装Apache yum install httpd httpd-devel 安装完成后,用/etc/ ...

  8. Python操作RabbitMQ初体验(一)

    由于想用Python实现一套分布式系统,来管理和监控CDN的内容与运行状态,误打误撞认识了RabbitMQ,推荐的人很多,如余锋<我为什么要选择RabbitMQ>等等. 在MQ这个词汇映入 ...

  9. Python: tkinter实例改名小工具

    #!/usr/bin/env python #coding=utf-8 # # 版权所有 2014 yao_yu (http://blog.csdn.net/yao_yu_126) # 本代码以MIT ...

  10. .NET基础之深度复制和浅度复制

    之前一直没有搞清楚深度复制和浅度复制的区别到底在哪里,今天彻底把这个东西弄懂了,写出来与到家共勉. 如果大家不懂值类型和引用类型的区别,请先看http://www.cnblogs.com/Autumo ...