MyBatis 源码分析——介绍
笔者第一次接触跟 MyBatis 框架是在 2009 年未的时候。不过那个时候的他并不叫 MyBatis,而是叫 IBatis。2010 年的时候改为现在的名字——MyBatis。这几年过去了,对于笔者来讲有一点陌生了。而且那个时候他也没有这么出名。hibernate 占了大部分市场。虽然笔者早年的时候查看过他的源码,但是并没有很深入去理解他。主要的原因是因为当时我还在看 hibernate 的源码。太累了所以就没有去认真的理解。现在笔者想要重新在来看一篇关于他的源码并加强对他的理解。也是对自己过程的一种回归吧。
想要查看源码就要先了解他的一些概念。否则云里来雾里去的什么也不懂。有很多朋友会选择去图书管买一些书来查看。当然这是可取的。那么如果不想的话,就可以去官网查看他们的介绍了——MyBatis 网站。笔者也会按照官网上面的介绍来进行源码上的查看。
ORM 思想的传播述造了很多 ORM 框架。事实上笔者也想把 MyBatis 定义为 ORM 框架。但是开发的过程中笔者感觉最多的是他在管理 SQL 语句。虽然在最后的结果会应射出对应的实体对象。可是还是我觉得 MyBatis 的管理 SQL 语句才是这个框架的核心。官网的介绍划分为四块来介绍 MyBatis——XML 配置、XML 映射文件、动态 SQL、日志。对于开发人员来讲主要看完这四块就可以了。当然关于什么是 ORM 的话,这个笔者就不在做什么相关的解释。网络上也有一片的资料足够你学习的。
学习环境
MyBatis 源码:mybatis-3-mybatis-3.4.1.
数据库:SQL SERVER 2008
开发工具:Ecilpse,Maven
Java:1.8
开发环境
官网上也有写一个篇关于入门的文章。 只是讲的可能简单了一点。但是这并不是没有任何作用。笔者用的是 Maven 来引入 MyBatis 的源码的。虽然他有自带的测试代码,不过笔者还是希望读者们能自己在新建一个项目来学习。这样子方便自己动手做一些测试来加深映像。虽然可以用 Maven 来构建 JAR。但是笔者没有这样子做。而是新建的项目里面引用 MyBatis 的源码。相信大家对 Ecilpse 里面的 Build Path 的 Projects 选择卡并不陌生。这样子方便查看源码,而不是在从 JAR 包中关联对应的源码。
上面的图片便是笔者导入之后项目源码。事实对我们学习最快最有用的应该是 test 这个部分的例子。你完全可以从例子中找到你不知道如何使用的功能点。
有了上面的源码,当然笔者也会简单的测试一下这个源码有没有错,能不能用。如下代码
public static void main(String[] args) { try {System.out.println(</span>"开始mybatis实验"<span style="color: rgba(0, 0, 0, 1)">); String resource </span>= "mybatis-config.xml"<span style="color: rgba(0, 0, 0, 1)">; InputStream inputStream </span>=<span style="color: rgba(0, 0, 0, 1)"> Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SqlSessionFactoryBuilder().build(inputStream); SqlSession session </span>=<span style="color: rgba(0, 0, 0, 1)"> sqlSessionFactory.openSession(); IProductMapper dao </span>= session.getMapper(IProductMapper.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); List</span><Product> products = dao.SelectProducts(30<span style="color: rgba(0, 0, 0, 1)">); session.close(); System.out.println(</span>"结束mybatis实验"<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) { e.printStackTrace(); } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) { e.printStackTrace(); } }</span></pre>
相信没有用看不懂这段代码。事实上我们可以知道想要用 MyBatis 就离不开他相关的配置信息。相对的 MyBatis 而言笔者觉得还是比较简的。笔者的例子项目里面有一个文件叫 mybatis-config.xml 文件。相信大家看了就知道他的作用。jdbc.properties 这个文件是存放了相关的数据库配置信息。可有可无,如果不要的话,就直接接在 dataSource 节点上直接修改数据库信息。
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">properties </span><span style="color: rgba(255, 0, 0, 1)">resource</span><span style="color: rgba(0, 0, 255, 1)">="jdbc.properties"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">environments </span><span style="color: rgba(255, 0, 0, 1)">default</span><span style="color: rgba(0, 0, 255, 1)">="development"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">environment </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="development"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">transactionManager </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="JDBC"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">dataSource </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="POOLED"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="driver"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${database.driver}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="url"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${database.url}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="username"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${database.username}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="password"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${database.password}"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">dataSource</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">environment</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">environments</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">mappers</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">mapper </span><span style="color: rgba(255, 0, 0, 1)">resource</span><span style="color: rgba(0, 0, 255, 1)">="com/aomi/dao/ProductMapper.xml"</span> <span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">mappers</span><span style="color: rgba(0, 0, 255, 1)">></span>
</configuration>
想要研究一个源码框架一定要找到切入口。从上面的例子代码中我们可以充分的分析出——SqlSessionFactoryBuilder 类就是源码的切入口。相信大家可能会想到常用的 JAVA 模式中的一种叫 Builder 模式。通过 SqlSessionFactoryBuilder 类的 build 方法我们可以拿到一个相关的类——SqlSessionFactory 类例化。实际就是 DefaultSqlSessionFactory 类。例子源码中我们可以看到后面的操作一定离不开 SqlSession 接口实例。而从名字上来讲,我们可以猜出 SqlSessionFactory 类好像是 SqlSession 接口的工厂类吧。当然这还要回头看一下源码才能确定。
在实例的开发过程中,我们一定会用到一个用于配置对象实体相关的配置文件。就是上面 XML 信息中的 Mapper 节点部分的信息。如下
<mappers> <mapper resource="com/aomi/dao/ProductMapper.xml" /> </mappers>
MyBatis 的亮点笔者认为就是管理 SQL 语句。不然笔者真觉得 MyBatis 好像也没有多大的优点。而类似上面的 XML 文件中就是存放 SQL 语句。当然一个实体对象可能对应一个 XML 文件。例如笔者写的例子一样子。如下
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.aomi.dao.IProductMapper">
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">select </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="SelectProducts"</span><span style="color: rgba(255, 0, 0, 1)"> resultMap</span><span style="color: rgba(0, 0, 255, 1)">="result"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> select * from Products where #{id} > ProductID </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">select</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">resultMap </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="com.aomi.vo.Product"</span><span style="color: rgba(255, 0, 0, 1)"> id</span><span style="color: rgba(0, 0, 255, 1)">="result"</span><span style="color: rgba(255, 0, 0, 1)"> autoMapping</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">resultMap</span><span style="color: rgba(0, 0, 255, 1)">></span>
</mapper>
关于如何管理 SQL 语句的话,笔者觉得你去查看官网来的更实际一点。而笔者想要讲的是不管是上面的 XML 配置文件,还是对实体的增删改查都离不开上面的 SqlSession 接口实例。看样子我们很清楚只要知道 SqlSession 接口实例的工作原理,就可以说理解了 70% 的 MyBatis 概念。