本文讨论 Spring 与 MyBatis 的整合。

在 beans.xml 中我们定义了两个 bean: SqlSessionFactoryBean、SqlSessionTemplate。

1、SqlSessionFactoryBean

a、SqlSessionFactoryBean 是 FactoryBean,它在 Spring 容器中通过 getObject() (单例模式)返回 SqlSessionFactory bean。源码如下:

   public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
} return this.sqlSessionFactory;
}

可以看出,SqlSessionFactoryBean 对 sqlSessionFactory 是懒加载。

b、afterPropertiesSet() 源码如下:

   public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required"); this.sqlSessionFactory = buildSqlSessionFactory();
}

afterPropertiesSet() 先检查 dataSource、sqlSessionFactoryBuilder 是否为 null。

dataSource 在 beans.xml 中设置,sqlSessionFactoryBuilder 在新建 sqlSessionFactoryBean 时会自动创建。

c、protected SqlSessionFactory buildSqlSessionFactory() throws Exception;

这个方法设置了 transactionFactory (默认为 SpringManagedTransactionFactory),生成 environment,放入 configuration 中。

然后对 mapperLocations(Resource[]) 进行解析,放入 configuration 的 mappedStatements 中。

最后调用 sqlSessionBuilder.build(configuration) 返回 sqlSessionFactory。

d、在 beans.xml 中给 SqlSessionFactoryBean 设置了 dataSource、mapperLocations 两个参数。

2、SqlSessionTemplate 构造方法接收一个 SqlSessionFactory 参数,最终会调用以下的构造方法:

 public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) { notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
notNull(executorType, "Property 'executorType' is required"); this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
}

sqlSessionFactory 默认 executorType 为 Simple,exceptionTranslator 为 MyBatisExceptionTranslator。

SqlSessionTemplate 可以加入到 Spring 的事务中,且线程安全,而 DefaultSqlSession 没有这两个特性。

3、DAO 层对数据库的访问最后都被 SqlSessionInterceptor 拦截。

这里用到了 JDK 反射功能。

private class SqlSessionInterceptor implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取sqlSession,其中包含了statement id
final SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
// 以下是事务管理
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
// 以下是异常管理,最后会抛出转换后的异常
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
// 关闭session
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}

可以看出,对 sqlSession 的获取和关闭、事务管理、异常管理都由这个内部类 SqlSessionInterceptor 负责;业务层只需专注 SQL 的编写,无需再关注对资源、事务及异常的管理。

代理的目的是加入透明的对资源、事务、异常的管理。

最终委托给 DefaultSqlSession 去访问数据库:从 configuration 获取 MappedStatement,由 Executor(默认 CachingExecutor)完成对 DB 的访问。

Spring 与 MyBatis 的整合的更多相关文章

  1. 关于Spring和mybatis的整合

    Spring同Mybatis的整合 1.引入相应的jar包.(Mybatis的jar包,Spring的jar包,mybatis-spring-1.1.1.jar). 2.编写相应的包(三层的包).搭建 ...

  2. 基于maven进行spring 和mybatis的整合(Myeclpise)

    学习日记:基于maven进行spring和mybatis的整合,进行分页查询 什么是maven:maven是一个项目管理工具,使用maven可以自动管理java项目的整个生命周期,包括编译.构建.测试 ...

  3. Spring+SpringMVC+MyBatis+easyUI整合基础篇(六)maven整合SSM

    写在前面的话   承接前文<Spring+SpringMVC+MyBatis+easyUI整合基础篇(五)讲一下maven>,本篇所讲述的是如何使用maven与原ssm项目整合,使得一个普 ...

  4. Spring+SpringMVC+MyBatis+easyUI整合基础篇(八)mysql中文查询bug修复

    写在前面的话 在测试搜索时出现的问题,mysql通过中文查询条件搜索不出数据,但是英文和数字可以搜索到记录,中文无返回记录.本文就是写一下发现问题的过程及解决方法.此bug在第一个项目中点这里还存在, ...

  5. Spring+SpringMVC+MyBatis+easyUI整合基础篇(十一)SVN服务器进阶

    日常啰嗦 上一篇文章<Spring+SpringMVC+MyBatis+easyUI整合基础篇(十)SVN搭建>简单的讲了一下SVN服务器的搭建,并没有详细的介绍配置文件及一些复杂的功能, ...

  6. Spring+SpringMVC+MyBatis+easyUI整合基础篇(十二)阶段总结

    不知不觉,已经到了基础篇的收尾阶段了,看着前面的十几篇文章,真的有点不敢相信,自己竟然真的坚持了下来,虽然过程中也有过懒散和焦虑,不过结果还是自己所希望的,克服了很多的问题,将自己的作品展现出来,也发 ...

  7. Spring+SpringMVC+MyBatis+easyUI整合优化篇(二)Log4j讲解与整合

    日常啰嗦 上一篇文章主要讲述了一下syso和Log间的一些区别与比较,重点是在项目的日志功能上,因此,承接前文<Spring+SpringMVC+MyBatis+easyUI整合优化篇(一)Sy ...

  8. Spring+SpringMVC+MyBatis+easyUI整合优化篇(四)单元测试实例

    日常啰嗦 前一篇文章<Spring+SpringMVC+MyBatis+easyUI整合优化篇(三)代码测试>讲了不为和不能两个状态,针对不为,只能自己调整心态了,而对于不能,本文会结合一 ...

  9. Spring+SpringMVC+MyBatis+easyUI整合优化篇(五)结合MockMvc进行服务端的单元测试

    日常啰嗦 承接前一篇文章<Spring+SpringMVC+MyBatis+easyUI整合优化篇(四)单元测试实例>,已经讲解了dao层和service层的单元测试,还有控制器这层也不能 ...

  10. Spring+SpringMVC+MyBatis+easyUI整合优化篇(七)图片上传功能

    日常啰嗦 前一篇文章<Spring+SpringMVC+MyBatis+easyUI整合优化篇(六)easyUI与富文本编辑器UEditor整合>讲了富文本编辑器UEditor的整合与使用 ...

随机推荐

  1. Python的return self和return一个新的对象区别

    目的:设计一个有理数相加.如3/5 + 7/15 = 80/75 return self 输入: class Rational0: def __init__(self, num, den=1): se ...

  2. POJ 1144 无向图求割点

     学长写的: #include<cstdio>#include<cstdlib>#include<cmath>#include<iostream>#in ...

  3. Linux FTP 上传一键脚本

    下面来介绍一下这个 FTP 上传一键脚本 ftp_upload.sh. 用途:用于在Linux系统下搭建FTP客户端向FTP服务器端上传文件: 总结一下 ftp_upload.sh 特点:1.支持文件 ...

  4. 经典的MapReduce1中的失败

    经典的MapReduce1中的失败在MapReduce1运行时,主要考虑三种失败的模式,运行任务失败.tasktracker失败以及jobtracker失败1. 任务运行失败首先考虑子任务失败的情况. ...

  5. session共享个人小结

    一.需求问题: 如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分发到不同的机器呢? 这个时候会话id在客户端是没有问题的, 但是如果用 ...

  6. ANT+JMETER集成2 (发送邮件)

    折腾一天发现各种build源码都不能发送邮件,试了很多次,终于能发送邮件 先看成果 build源码贴出来 <?xml version="1.0" encoding=" ...

  7. 云服务器pip下载老失败怎么办?

    pip install -i https://pypi.douban.com/simple django==1.9

  8. php特级课---2、网站大数据如何存储

    php特级课---2.网站大数据如何存储 一.总结 一句话总结: mysql主从,分库分表,mysql分区,mysql集群,Nosql 1.mysql主从服务器各自的功能是什么? 增删改,主服务器 查 ...

  9. javascript 跨域问题解决办法总结

    跨域的意思就是不同域名之间的页面默认是无法通信的.因为浏览器默认是禁止跨域的: 图所示:chrome浏览器尝试获取mainFrame失败,提示DomException 1).假如你有个网站 a.com ...

  10. webservice 交错数组

    net webservices public DataSet SelectOPQuestionByWhere(string strWhere, string[][] strArry) { if (!k ...