搞java的想提高自己的姿势水平,想拿高工资,对常用开源框架的深入了解是必不可少的,想深入了解源码分析更是必不可少的,今天我开始对mybatis的源码进行分析,并做点记录以备查验。开源框架研究,文档的获取建议去读官方的文档和例子,这样获得的知识成体系,成体系的知识被你掌握了,你就可以说你精通它了。好了,开始吧。
上面说道要看官方的文档,那么就得找到官方网站什么的对吧?这里给几个网站都是不错的:
Myabtis官网:http://www.mybatis.org/
github地址:https://github.com/mybatis/mybatis-3
这里我使用mybatis-3.1.1版本做分析,更新的版本自己去github下吧,好了这是下载到的项目:
起一个项目来边写代码,边分析!
1.新建一个工程,web或者java工程都可以,将以下的jar包拷到lib目录并buildPath:
2.在src目录下创建mybatis配置文件Configuration.xml,代码如下:
<?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> <typeAliases> <typeAlias alias="AdminPermissionGroup" type="com.raykip.study.mybatis.model.AdminPermissionGroup"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8" /> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/raykip/study/mybatis/model/AdminPermissionGroup.xml"/> </mappers> </configuration>
3.准备一下测试数据吧:
/* Navicat MySQL Data Transfer Source Server : raykipp Source Server Version : 50627 Source Host : 127.0.0.1:3306 Source Database : test Target Server Type : MYSQL Target Server Version : 50627 File Encoding : 65001 Date: 2016-05-15 11:21:37 */SET FOREIGN_KEY_CHECKS=0;-- ------------------------------ Table structure for `t_admin_permission_group`-- ----------------------------DROPTABLEIFEXISTS`t_admin_permission_group`;CREATETABLE`t_admin_permission_group` ( `groupId`bigint(20) NOTNULL AUTO_INCREMENT COMMENT'权限组表Id', `groupName`varchar(20) DEFAULTNULLCOMMENT'权限名称', `status`int(10) DEFAULTNULLCOMMENT'状态,1表示有效,0表示无效', `orderId`int(10) DEFAULT'0'COMMENT'排序号', `creater`varchar(20) DEFAULTNULLCOMMENT'创建者', `createTime` datetime DEFAULTNULLCOMMENT'创建时间', `modifyer`varchar(20) DEFAULTNULLCOMMENT'修改者', `modifyTime` datetime DEFAULTNULLCOMMENT'修改时间', PRIMARY KEY (`groupId`) ) ENGINE=InnoDB AUTO_INCREMENT=13DEFAULTCHARSET=utf8;-- ------------------------------ Records of t_admin_permission_group-- ----------------------------INSERTINTO`t_admin_permission_group`VALUES ('1', '用户管理', '1', '1', 'wxh', '2015-06-21 09:41:35', 'wxh', '2015-06-21 09:41:43');
4.看到上面的xml里面配有AdminPermissionGroup实体类和它的映射文件,代码如下:
AdminPermissionGroup.java
package com.raykip.study.mybatis.model; import java.sql.Timestamp; publicclassAdminPermissionGroup { /**权限组表Id*/private Long groupId; /**权限组名称*/private String groupName; /**状态,1表示有效,0表示无效*/privateint status; /**排序号*/privateint orderId; /**创建者*/private String creater; /**创建时间*/private Timestamp createTime; /**修改者*/private String modifyer; /**修改时间*/private Timestamp modifyTime; public Long getGroupId() { return groupId; } publicvoidsetGroupId(Long groupId) { this.groupId = groupId; } public String getGroupName() { return groupName; } publicvoidsetGroupName(String groupName) { this.groupName = groupName; } publicintgetStatus() { return status; } publicvoidsetStatus(int status) { this.status = status; } publicintgetOrderId() { return orderId; } publicvoidsetOrderId(int orderId) { this.orderId = orderId; } public String getCreater() { return creater; } publicvoidsetCreater(String creater) { this.creater = creater; } public Timestamp getCreateTime() { return createTime; } publicvoidsetCreateTime(Timestamp createTime) { this.createTime = createTime; } public String getModifyer() { return modifyer; } publicvoidsetModifyer(String modifyer) { this.modifyer = modifyer; } public Timestamp getModifyTime() { return modifyTime; } publicvoidsetModifyTime(Timestamp modifyTime) { this.modifyTime = modifyTime; } }
<pre name="code" class="html" style="font-size: 14px; line-height: 21px; widows: 1;">AdminPermissionGroup.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="AdminPermissionGroup" > <resultMap id="BaseResultMap" type="com.raykip.study.mybatis.model.AdminPermissionGroup" > <id column="groupId" property="groupId" jdbcType="BIGINT" /> <result column="groupName" property="groupName" jdbcType="VARCHAR" /> <result column="status" property="status" jdbcType="INTEGER" /> <result column="orderId" property="orderId" jdbcType="INTEGER" /> <result column="creater" property="creater" jdbcType="VARCHAR" /> <result column="createTime" property="createTime" jdbcType="TIMESTAMP" /> <result column="modifyer" property="modifyer" jdbcType="VARCHAR" /> <result column="modifyTime" property="modifyTime" jdbcType="TIMESTAMP" /> </resultMap> <sql id="Base_Column_List" > groupId,groupName,status,orderId,creater,createTime,modifyer,modifyTime </sql> <!-- #是特殊字符只能通过定义变量间接输出 --> <!-- 按id查找--> <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" > select <include refid="Base_Column_List" /> from t_admin_permission_group where groupId = #{groupId,jdbcType=BIGINT} </select> <!-- 按对象查找--> <select id="selectByObject" resultMap="BaseResultMap" parameterType="com.raykip.study.mybatis.model.AdminPermissionGroup" > select <include refid="Base_Column_List" /> from t_admin_permission_group where 1=1 <if test="groupId != null" > and groupId = #{groupId,jdbcType=BIGINT} </if> <if test="groupName != null" > and groupName = #{groupName,jdbcType=VARCHAR} </if> <if test="status != null" > and status = #{status,jdbcType=INTEGER} </if> <if test="orderId != null and orderId != 0" > and orderId = #{orderId,jdbcType=INTEGER} </if> <if test="creater != null" > and creater = #{creater,jdbcType=VARCHAR} </if> <if test="createTime != null" > and createTime = #{createTime,jdbcType=TIMESTAMP} </if> <if test="modifyer != null" > and modifyer = #{modifyer,jdbcType=VARCHAR} </if> <if test="modifyTime != null" > and modifyTime = #{modifyTime,jdbcType=TIMESTAMP} </if> order by groupId </select> <!-- 统计总数 --> <select id="countAll" resultType="java.lang.Integer"> select count(1) as count from t_admin_permission_group </select> <!-- 统计总数(部分) --> <select id="countSelective" resultType="java.lang.Integer" parameterType="com.raykip.study.mybatis.model.AdminPermissionGroup"> select count(1) as count from t_admin_permission_group where 1=1 <if test="groupId != null" > and groupId = #{groupId,jdbcType=BIGINT} </if> <if test="groupName != null" > and groupName = #{groupName,jdbcType=VARCHAR} </if> <!-- <if test="status != null" > and status = #{status,jdbcType=INTEGER} </if> --> <if test="orderId != null and orderId != 0" > and orderId = #{orderId,jdbcType=INTEGER} </if> <if test="creater != null" > and creater = #{creater,jdbcType=VARCHAR} </if> <if test="createTime != null" > and createTime = #{createTime,jdbcType=TIMESTAMP} </if> <if test="modifyer != null" > and modifyer = #{modifyer,jdbcType=VARCHAR} </if> <if test="modifyTime != null" > and modifyTime = #{modifyTime,jdbcType=TIMESTAMP} </if> </select> <!-- 分页&条件查询--> <select id="selectByObjectLimit" resultMap="BaseResultMap" parameterType="com.raykip.study.mybatis.model.AdminPermissionGroup" > select <include refid="Base_Column_List" /> from t_admin_permission_group where 1=1 <if test="groupId != null" > and groupId = #{groupId,jdbcType=BIGINT} </if> <if test="groupName != null" > and groupName = #{groupName,jdbcType=VARCHAR} </if> <!-- <if test="status != null" > and status = #{status,jdbcType=INTEGER} </if> --> <if test="orderId != null and orderId != 0" > and orderId = #{orderId,jdbcType=INTEGER} </if> <if test="creater != null" > and creater = #{creater,jdbcType=VARCHAR} </if> <if test="createTime != null" > and createTime = #{createTime,jdbcType=TIMESTAMP} </if> <if test="modifyer != null" > and modifyer = #{modifyer,jdbcType=VARCHAR} </if> <if test="modifyTime != null" > and modifyTime = #{modifyTime,jdbcType=TIMESTAMP} </if> </select> <!-- 多条件查询--> <select id="selectListByObject" resultMap="BaseResultMap" parameterType="com.raykip.study.mybatis.model.AdminPermissionGroup" > select <include refid="Base_Column_List" /> from t_admin_permission_group where 1=1 <if test="groupId != null" > and groupId = #{groupId,jdbcType=BIGINT} </if> <if test="groupName != null" > and groupName = #{groupName,jdbcType=VARCHAR} </if> <if test="status != null" > and status = #{status,jdbcType=INTEGER} </if> <if test="orderId != null and orderId != 0" > and orderId = #{orderId,jdbcType=INTEGER} </if> <if test="creater != null" > and creater = #{creater,jdbcType=VARCHAR} </if> <if test="createTime != null" > and createTime = #{createTime,jdbcType=TIMESTAMP} </if> <if test="modifyer != null" > and modifyer = #{modifyer,jdbcType=VARCHAR} </if> <if test="modifyTime != null" > and modifyTime = #{modifyTime,jdbcType=TIMESTAMP} </if> </select> <!-- 插入数据--> <insert id="insert" parameterType="com.raykip.study.mybatis.model.AdminPermissionGroup" > insert into t_admin_permission_group ( groupId,groupName,status,orderId,creater,createTime,modifyer,modifyTime ) values ( #{groupId,jdbcType=BIGINT}, #{groupName,jdbcType=VARCHAR}, #{status,jdbcType=INTEGER}, #{orderId,jdbcType=INTEGER}, #{creater,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{modifyer,jdbcType=VARCHAR}, #{modifyTime,jdbcType=TIMESTAMP} ) </insert> <!-- 插入数据(部分字段)--> <insert id="insertSelective" parameterType="com.raykip.study.mybatis.model.AdminPermissionGroup" > insert into t_admin_permission_group <trim prefix="(" suffix=")" suffixOverrides="," > <if test="groupId != null" > groupId, </if> <if test="groupName != null" > groupName, </if> <if test="status != null" > status, </if> <if test="orderId != null and orderId != 0" > orderId, </if> <if test="creater != null" > creater, </if> <if test="createTime != null" > createTime, </if> <if test="modifyer != null" > modifyer, </if> <if test="modifyTime != null" > modifyTime, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides="," > <if test="groupId != null" > #{groupId,jdbcType=BIGINT}, </if> <if test="groupName != null" > #{groupName,jdbcType=VARCHAR}, </if> <if test="status != null" > #{status,jdbcType=INTEGER}, </if> <if test="orderId != null" > #{orderId,jdbcType=INTEGER}, </if> <if test="creater != null" > #{creater,jdbcType=VARCHAR}, </if> <if test="createTime != null" > #{createTime,jdbcType=TIMESTAMP}, </if> <if test="modifyer != null" > #{modifyer,jdbcType=VARCHAR}, </if> <if test="modifyTime != null" > #{modifyTime,jdbcType=TIMESTAMP}, </if> </trim> </insert> <!-- 批量插入数据--> <insert id="batchInsert" parameterType="java.util.List"> insert into t_admin_permission_group (groupId,groupName,status,orderId,creater,createTime,modifyer,modifyTime) values <foreach collection="list" item="item" index="index" separator=","> ( #{groupId,jdbcType=BIGINT}, #{groupName,jdbcType=VARCHAR}, #{status,jdbcType=INTEGER}, #{orderId,jdbcType=INTEGER}, #{creater,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{modifyer,jdbcType=VARCHAR}, #{modifyTime,jdbcType=TIMESTAMP} ) </foreach> </insert> <!-- 删除数据--> <delete id="deleteByPrimaryKey" parameterType="java.lang.Long" > delete from t_admin_permission_group where groupId = #{groupId,jdbcType=BIGINT} </delete> <!-- 更新数据(部分字段)--> <update id="updateByPrimaryKeySelective" parameterType="com.raykip.study.mybatis.model.AdminPermissionGroup" > update t_admin_permission_group <set > <if test="groupName != null" > groupName = #{groupName,jdbcType=VARCHAR}, </if> <if test="status != null" > status = #{status,jdbcType=INTEGER}, </if> <if test="orderId != null and orderId != 0" > orderId = #{orderId,jdbcType=INTEGER}, </if> <if test="creater != null" > creater = #{creater,jdbcType=VARCHAR}, </if> <if test="createTime != null" > createTime = #{createTime,jdbcType=TIMESTAMP}, </if> <if test="modifyer != null" > modifyer = #{modifyer,jdbcType=VARCHAR}, </if> <if test="modifyTime != null" > modifyTime = #{modifyTime,jdbcType=TIMESTAMP} </if> </set> where groupId = #{groupId,jdbcType=BIGINT} </update> <!-- 更新数据--> <update id="updateByPrimaryKey" parameterType="com.raykip.study.mybatis.model.AdminPermissionGroup" > update t_admin_permission_group set groupName = #{groupName,jdbcType=VARCHAR}, status = #{status,jdbcType=INTEGER}, orderId = #{orderId,jdbcType=INTEGER}, creater = #{creater,jdbcType=VARCHAR}, createTime = #{createTime,jdbcType=TIMESTAMP}, modifyer = #{modifyer,jdbcType=VARCHAR}, modifyTime = #{modifyTime,jdbcType=TIMESTAMP} where groupId = #{groupId,jdbcType=BIGINT} </update> <!-- 批量更新数据 --> <update id="batchUpdate" parameterType="map"> update t_admin_permission_group <set > groupId = #{groupId,jdbcType=BIGINT}, groupName = #{groupName,jdbcType=VARCHAR}, status = #{status,jdbcType=INTEGER}, orderId = #{orderId,jdbcType=INTEGER}, creater = #{creater,jdbcType=VARCHAR}, createTime = #{createTime,jdbcType=TIMESTAMP}, modifyer = #{modifyer,jdbcType=VARCHAR}, modifyTime = #{modifyTime,jdbcType=TIMESTAMP} </set> where groupId in <foreach collection="list" item="item" index="index" open="(" separator="," close=")" > #{item.groupId} </foreach> </update> </mapper>
5.写一个测试类测试一下吧!
package com.raykip.study.mybatis.test; import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import com.alibaba.fastjson.JSON; import com.raykip.study.mybatis.model.AdminPermissionGroup; public class SqlsessionTest{ privatestaticSqlSessionFactory sqlSessionFactory; privatestaticReader reader; static{ try{ reader = Resources.getResourceAsReader("Configuration.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); }catch(Exception e){ e.printStackTrace(); } } publicstaticSqlSessionFactory getSession(){ return sqlSessionFactory; } publicstatic void main(String[] args) { SqlSession session = sqlSessionFactory.openSession(); try { AdminPermissionGroup group = (AdminPermissionGroup) session.selectOne("AdminPermissionGroup.selectByPrimaryKey", 1); System.out.println(JSON.toJSONString(group)); } finally { session.close(); } } }
6.运行结果如下:
log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. {"createTime":1434850895000,"creater":"wxh","groupId":1,"groupName":"用户管理","modifyTime":1434850903000,"modifyer":"wxh","orderId":1,"status":1}
这些是结果,接下来结合SqlsessionTest类来分析源码!
1.在本类中先定义了一个SqlSessionFactory接口,完整接口名是org.apache.ibatis.session.SqlSessionFactory,源码如下:
/* * Copyright 2009-2012 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.apache.ibatis.session; import java.sql.Connection; publicinterfaceSqlSessionFactory{ SqlSession openSession(); SqlSession openSession(boolean autoCommit); SqlSession openSession(Connection connection); SqlSession openSession(TransactionIsolationLevel level); SqlSession openSession(ExecutorType execType); SqlSession openSession(ExecutorType execType, boolean autoCommit); SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level); SqlSession openSession(ExecutorType execType, Connection connection); Configuration getConfiguration(); }
我们看到这个接口主要定义了openSeeion、getConfiguration这2个接口,如果你用过hibernate应该能猜到一个打开seesion,一个是用来获取配置信息的,接下来看一下它们的实现类:
http://tool.oschina.net/apidocs/apidoc?api=mybatis-3.1.1这个文档有这2个类的说明,也就是说你可以使用这2个类来获取sqlSessionFactory,比如: sqlSessionFactory = SqlSessionManager.newInstance(reader); 或者 DataSource dataSource = new PooledDataSource("com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1:3306/circcenter?useUnicode=true&characterEncoding=UTF-8", "root", "root"); Environment environment = new Environment("test", new JdbcTransactionFactory(), dataSource); Configurationconfiguration = newConfiguration(environment); configuration.addMapper(AdminPermissionGroup.class); //SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); sqlSessionFactory = new DefaultSqlSessionFactory(configuration);
通过看代码,发现SqlSessionFactoryBuilder类起到关键作用,OK我们看一下这个类:
首先用Eclipse工具查看SqlSessionFactoryBuilder类的Outline视图:
其实这个三个方法才是最重要的:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) public SqlSessionFactory build(Reader reader, String environment, Properties properties) public SqlSessionFactory build(Configuration config)
我们来看一下build方法的源码:
public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } }
通过上面这几行代码,就能看出基于XML文件的这种构造方式,通过从XML中读取信息的工作之后,也是构造出Configuration对象之后再继续进行SqlSessionFactory的构建工作的,只是多了些XML的解析工作,所以我们只需单刀直入,直按分析编程构造方式的代码就可以了,或者是直接分析 build(parser.parse())这句代码(参数产生过程先跳过)
编程构造方式的build方法源码如下(基于xml的构造方式的build(parser.parse())最终也是调了这个代码):
public SqlSessionFactory build(Configuration config) { returnnew DefaultSqlSessionFactory(config); }
其实这么看来SqlSessionFactory在mybatis的默认实现类为org.apache.ibatis.session.defaults.DefaultSqlSessionFactory , 其构造过程主要是注入了Configuration的实例对象,Configuration的实例对象即可通过解析xml配置文件产生,也可能通过代码直接构造。以上代码使用了一个设计模式:建设者模式(Builder),SqlSessionFactoryBuilder扮演具体的建造者,Configuration类则负责建造的细节工作,SqlSession则是建造出来的产品。
以下是类图和建造者模式的基本形态图,读者自行对照阅读。
构造者模式是一种对象的创建模式。它可以将一个复杂对象的内部构成特征与对象的构建过程完全分开。
在本类中使用static静态块初始化了sqlsessionFactory,在实际项目中会写一个单例类获取sqlsessionFactory或者获取Sqlsession,原因和Hibernate一样,这个类加载比较消耗资源。例如:
package com.raykip.study.mybatis.util;
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
publicclassSqlSessionFactoryUtil{ privatestatic SqlSessionFactory sqlSessionFactory;
publicstatic SqlSessionFactory getSqlSessionFactory()throws IOException{
if(sqlSessionFactory==null){
Reader reader = Resources.getResourceAsReader("Configuration.xml");
returnnew SqlSessionFactoryBuilder().build(reader);
}else{
return sqlSessionFactory;
}
}
}
好了,我们再来看下Sqlsession这个接口,我相信大家对这个类不会陌生,它是一个会话,与数据库的会话,通过它可以执行sql返回结果集、提交/回滚事务等操作。还是看一下outline图:
相信看到这些方法,可以猜到这些方法是干嘛的,包含的select、insert、update、delete方法都是基本的数据库操作,我们可以利用这些方法封装我们自己的BaseDao,并进行扩展。实现类有这2个:
我们先看一下测试类中使用的public <T> T selectOne(String statement, Object parameter) 方法,这个方法的作用显然是返回一个结果集,源码如下:
public <T> T selectOne(String statement, Object parameter){
// Popular vote was to return null on 0 results and throw exception on too many.
List<T> list = this.<T>selectList(statement, parameter);
if (list.size() == 1) {
returnlist.get(0);
} elseif (list.size() > 1) {
thrownew TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
我们看到其实它调用的是this.<T>selectList(statement, parameter)方法,好吧继续:
public <E> List<E> selectList(String statement, Object parameter) {
return this.<E>selectList(statement, parameter, RowBounds.DEFAULT);
}
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
List<E> result = executor.<E>query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
returnresult;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
这里已经比较复杂了,必须通过debug来领会代码的含义:
通过设置断点,selectList方法中首先取到了MappedStatement,MappedStatement类在Mybatis框架中用于表示XML文件中一个sql语句节点,即一个<select
/>、<update />或者<insert />标签。Mybatis框架在初始化阶段会对XML配置文件进行读取,将其中的sql语句节点对象化为一个个MappedStatement对象。
也就是说mybatis通过<mapper>标签的namespace和<select>标签的id属性找到指定的sql。现在这里取到的statement是AdminPermissionGroup.selectByPrimaryKey,就是我们调用selectOne传进来的参数,parameter=1也是我们传进来的参数,我们继续看它是怎么找到sql的:
发现如果validateIncompleteStatements为false,跳到了这里:
原来是Configuration类的mappedStatements属性,原来当加载AdminPermissionGroup.xml文件时,xml的每个节点都被加载到了mappedStatements这个map中。
{countAll=[email protected], AdminPermissionGroup.selectByPrimaryKey=[email protected]be2c3, AdminPermissionGroup.selectByObject=[email protected], batchInsert=[email protected], updateByPrimaryKeySelective=[email protected], batchUpdate=[email protected], insert=[email protected], selectListByObject=[email protected], AdminPermissionGroup.selectByObjectLimit=[email protected], AdminPermissionGroup.deleteByPrimaryKey=[email protected], selectByPrimaryKey=[email protected], selectByObjectLimit=[email protected], AdminPermissionGroup.insertSelective=[email protected], AdminPermissionGroup.batchInsert=[email protected], updateByPrimaryKey=[email protected], insertSelective=[email protected], AdminPermissionGroup.selectListByObject=[email protected], AdminPermissionGroup.insert=[email protected], countSelective=[email protected], AdminPermissionGroup.updateByPrimaryKey=[email protected], AdminPermissionGroup.updateByPrimaryKeySelective=[email protected], AdminPermissionGroup.batchUpdate=[email protected], deleteByPrimaryKey=[email protected], AdminPermissionGroup.countSelective=[email protected], AdminPermissionGroup.countAll=[email protected], selectByObject=[email protected]}
但是这里的validateIncompleteStatements的意思是校验Statement是否正确的含义,源码如下:
最终还是会从mappedStatements这个map中取到对应的select节点,而我们的sql就存在MappedStatement对象的sqlSource属性中,通过getBoundSql方法获取的:
从这段代码中我们可以看到,mybatis默认是会缓存结果集的:
由于有缓存这个方法就直接看最后一段:
接下来就快到了JDBC的代码了:
我们看到最终还是调用了JDBC的代码,可见mybatis对了JDBC做了封装,也就是说当mybatis不能满足我们的需要的时候,我们可以扩展的方式取到PreparedStatement使用JDBC的代码来完成我们的需求。那么接下来就是对JDBC返回的结果集进行封装、包装成resultMap设定的实体类了:
public List<Object> handleResultSets(Statement stmt) throws SQLException {
finalList<Object> multipleResults = new ArrayList<Object>();
finalList<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
int resultSetCount = 0;
ResultSet rs = stmt.getResultSet();
while (rs == null) {
// move forward to get the first resultset in case the driver// doesn‘t return the resultset as the first result (HSQLDB 2.1)if (stmt.getMoreResults()) {
rs = stmt.getResultSet();
} else {
if (stmt.getUpdateCount() == -1) {
// no more results. Must be no resultsetbreak;
}
}
}
validateResultMapsCount(rs, resultMapCount);
while (rs != null && resultMapCount > resultSetCount) {
final ResultMap resultMap = resultMaps.get(resultSetCount);
ResultColumnCache resultColumnCache = new ResultColumnCache(rs.getMetaData(), configuration);
handleResultSet(rs, resultMap, multipleResults, resultColumnCache);
rs = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
return collapseSingleResultList(multipleResults);
}
resultHandler这里可以对结果集进行自定义的操作,也可以自己实现一个resultHandler覆盖这个里的resultHandler:
这里按实体类的属性类型获取值:
好了,今天先分析到这里,谢谢大家!