【mybatis】mybatis工作原理底层源码全流程解析

database

mybatis 工作原理

1. SqlSessionFactory 初始化

作用:加载Mybatis配置,用于生成SqlSession用于数据库操作

// 加载mybatis全局配置文件,生成SqlSessionFactory

InputStream inputStream = Resources.getResourceAsStream(factedfilePath);

sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

全局配置文件:SqlMapConfig.xml

<configuration>

<!-- myybatis 变量 -->

<properties resource="db.properties"/>

<!-- 实体别名,用于ResultMap映射 -->

<typeAliases>

<package name="com.zhiwei.entity"/>

</typeAliases>

<!-- 累心处理器:用于ResultSetHandler解析 -->

<typeHandlers>

<typeHandler handler="com.zhiwei.advanced.type.AddressTypeHandler"/>

</typeHandlers>

<!-- 环境配置: 主要包含数据库配置-->

<environments default="development">

<environment id="development">

<transactionManager type="JDBC"/>

<dataSource type="POOLED">

<property name="driver" value="${jdbc.driver}"/>

<property name="url" value="${jdbc.url}"/>

<property name="username" value="${jdbc.user}"/>

<property name="password" value="${jdbc.password}"/>

</dataSource>

</environment>

</environments>

<!-- mapper接口映射:classpath下,注意maven打包需配置引入XML资源 -->

<mappers>

<mapper resource="advanced/StudentMapper.xml"/>

</mappers>

</configuration>

1.0 解析SqlMapConfig.xml

代码:org.apache.ibatis.session.SqlSessionFactoryBuilder#build

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {

try {

// 本质由XMLConfigBuilder解析生成Configuration对象,由Configuration初始化SqlSessionFactory

parser = new XMLConfigBuilder(inputStream, environment, properties);

return build(parser.parse());

} catch (Exception e) {

throw ExceptionFactory.wrapException("Error building SqlSession.", e);

} finally {

ErrorContext.instance().reset();

try {

inputStream.close();

} catch (IOException e) {

// Intentionally ignore. Prefer previous error.

}

}

}

1.1 XMLConfigBuilder解析配置,生成Configuration

Configuration: 包含mybatis所有环境配置信息:例如

  • MapperRegistry: mapper接口注册信息,用于后续动态代理处理数据库逻辑
  • InterceptorChain: mybatis拦截器,用于mybatis各个阶段功能加强,例如监控、分页等
  • TypeHandlerRegistry: 用于ResultSetHandler解析ResultSet时的数据转换,例如数据库存储JOSN字符串,可解析成对象
  • TypeAliasRegistry:类型别名注册,包含指定类的别名,ResultMap时可直接映射
  • mappedStatements:包含Mapper.xml文件配置所有信息,对应CRUD的XML片段(业务执行核心)
  • keyGenerators: 主键自动生成器,类似mysql auto_increment 主键自动增长功能
  • resultMaps: resultMap 配置信息(数据库响应字段与实体映射)
  • parameterMaps: parameterMap 配置信息(请求实体字段与数据库字段映射)
  • environment: 环境信息,包含数据库相关配置,封装数据源和事务工厂

源码:org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration

private void parseConfiguration(XNode root) {

try {

//解析mybatis变量属性:对应标签:<properties resource="db.properties"/>

propertiesElement(root.evalNode("properties"));

//解析settings标签,并作做字段校验,防止非法字段

Properties settings = settingsAsProperties(root.evalNode("settings"));

// 加载Vfs配置:虚拟文件系统配置数据:vfsImpl

loadCustomVfs(settings);

// 加载自定义日志实现 logImpl

loadCustomLogImpl(settings);

// 类别名解析:对应标签:案例将包com.zhiwei.entity下实力映射别名,例如类Student,别名为student,ResultMap可直接引用

// <typeAliases>

// <package name="com.zhiwei.entity"/>

// </typeAliases>

typeAliasesElement(root.evalNode("typeAliases"));

//插件解析:用于Mybatis拦截器处理:interceptorChain

pluginElement(root.evalNode("plugins"));

// 对象工厂解析,用于创建对象、设置属性等操作(工具类)

objectFactoryElement(root.evalNode("objectFactory"));

// 对象包装器工厂,类似Spring Bean和BeanWrapper的关系,用于生成包装对象

objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));

// 反射器工厂:缓存类和类反射器,用于反射操作

reflectorFactoryElement(root.evalNode("reflectorFactory"));

//应用mybatis最终配置,例如cacheEnabled 默认开启二级缓存

settingsElement(settings);

//mybatis环境配置:主要封装数据库信息

environmentsElement(root.evalNode("environments"));

//databaseIdProvider:用于标识environment配置的数据源,例如Oracle、MYSQL产品名称

databaseIdProviderElement(root.evalNode("databaseIdProvider"));

// 类型处理器:主要用于数据库查询返回后,字段与实体对应,例如数据库存储为JSON,实际实体属性为对象,这里就需类型处理器进行转换

typeHandlerElement(root.evalNode("typeHandlers"));

// mapper.xml解析: 底层实现:org.apache.ibatis.builder.xml.XMLMapperBuilder.parse

// MappedStatement: 对应CRUD的SQL片段,唯一标识:namespace+id

mapperElement(root.evalNode("mappers"));

} catch (Exception e) {

throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);

}

}

1.2 MappedStatement 生成逻辑

案例:StudentMapper.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.zhiwei.advanced.mapper.StudentMapper">

<resultMap type="com.zhiwei.entity.Student" id="studentResultMap">

<id column="sid" property="sid"/>

<result column="name" property="name"/>

<result column="password" property="password"/>

<result column="age" property="age"/>

<result column="gender" property="gender" javaType="java.lang.String"/>

<result column="score" property="score" javaType="java.lang.Integer"/>

<result column="address" property="address" typeHandler="com.zhiwei.advanced.type.AddressTypeHandler"/>

</resultMap>

<!-- MappedStatement主题 -->

<select id="findStudentById" parameterType="int" resultMap="studentResultMap">

select * from student where sid = #{sid}

</select>

</mapper>

源码:org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement

private void configurationElement(XNode context) {

//context XNode对应标签:<mapper namespace="com.zhiwei.advanced.mapper.StudentMapper">

try {

//获取namespace: com.zhiwei.advanced.mapper.StudentMapper

String namespace = context.getStringAttribute("namespace");

if (namespace == null || namespace.equals("")) {

throw new BuilderException("Mapper"s namespace cannot be empty");

}

//工具类MapperBuilderAssistant设置当前处理的Mapper文件,namespace标识

builderAssistant.setCurrentNamespace(namespace);

// 缓存引用处理,实现多个Mapper共享相同的缓存,缓存由Configuration caches维护

cacheRefElement(context.evalNode("cache-ref"));

// 缓存处理:mapper级别缓存控制,默认全局Setting(settingsElement(settings))配置cacheEnabled开启二级缓存,Configuration维护也一份缓存供其他Mapper引用:cache-ref

cacheElement(context.evalNode("cache"));

// parameterMap维护:用于映射请求实体和数据库字段(基本弃用,parameterType代替)

parameterMapElement(context.evalNodes("/mapper/parameterMap"));

//resultMap 数据库查询结果集映射

resultMapElements(context.evalNodes("/mapper/resultMap"));

// sql解析,封装到MappedStatement sqlSource属性

sqlElement(context.evalNodes("/mapper/sql"));

// 构建MappedStatement对象(CRUD操作才被被映射成MappedStatement)

buildStatementFromContext(context.evalNodes("select|insert|update|delete"));

} catch (Exception e) {

throw new BuilderException("Error parsing Mapper XML. The XML location is "" + resource + "". Cause: " + e, e);

}

}

2. SqlSession 执行数据库操作

案例:

StudentMapper.java:

public interface StudentMapper {

public Student findStudentById(Integer sid);

}

SqlSession sqlSession = sqlSessionFactory.openSession();

StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

studentMapper.findStudentById(id);

2.1 获取SqlSession的方式

案例:SqlSession sqlSession = sqlSessionFactory.openSession();

解析:因是Select操作,不设计数据变更,采用默认的autoCommit=true,自动提交事务,本质和java.sql.Connection.setAutoCommit(true)一样,执行1个操作就自动提交事务

底层源码:org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.openSessionFromDataSource

 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {

Transaction tx = null;

try {

// 获取mybatis环境变量,主要用于构建事务工厂,为后续数据库操作做好准备

final Environment environment = configuration.getEnvironment();

final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);

// 基于数据源创建事务:JdbcTransaction(Connection 数据库连接、dataSource 数据源、level 数据库隔离级别、autoCommit 是否自动提交事务)

tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

// 执行器: 所有数据库操作底层都是交给Executor负责调度

final Executor executor = configuration.newExecutor(tx, execType);

// 创建SqlSession,包含mybatis配置、数据库操作执行器、事务自动提交标识

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.2 executor创建逻辑

源码:org.apache.ibatis.session.Configuration.newExecutor

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {

//executorType: 执行器类型,默认Simple,可自定义:org.apache.ibatis.session.Configuration.defaultExecutorType

executorType = executorType == null ? defaultExecutorType : executorType;

executorType = executorType == null ? ExecutorType.SIMPLE : executorType;

Executor 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);

}

// 默认开启二级缓存,自动创建CachingExecutor,包装SimpleExecutor,二级缓存存储在TransactionalCacheManager,

// 注意开启Mapper二级缓存需要定义cache标签或者引用别的Mapper缓存:cache-ref

// 二级缓存开启步骤:

// 1. 全局开启: 默认开启 (configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));)

// 2. mapper.xml cache 开启

if (cacheEnabled) {

executor = new CachingExecutor(executor);

}

executor = (Executor) interceptorChain.pluginAll(executor);

return executor;

}

3. Mapper 生成逻辑(JDK 动态代理)

案例代码:StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

MapperRegistry:映射器注册表,主要维护Mapper接口和代理对象工厂,用于生成Mapper代理对象,用以实际的数据库业务处理

底层源码:org.apache.ibatis.binding.MapperRegistry.getMapper

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {

final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);

if (mapperProxyFactory == null) {

throw new BindingException("Type " + type + " is not known to the MapperRegistry.");

}

try {

// 映射器动态代理工厂生成mapper接口动态代理对象

return mapperProxyFactory.newInstance(sqlSession);

} catch (Exception e) {

throw new BindingException("Error getting mapper instance. Cause: " + e, e);

}

}

3.1 mapperProxyFactory生成Mapper动态代理对象

public T newInstance(SqlSession sqlSession) {

final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);

return newInstance(mapperProxy);

}

@SuppressWarnings("unchecked")

protected T newInstance(MapperProxy<T> mapperProxy) {

// JDK1.8 动态代理对象生成

return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);

}

3.2 MapperProxy 动态代理对象

MapperProxy实现动态代理接口:InvocationHandler

源码:org.apache.ibatis.binding.MapperProxy.invoke

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

try {

if (Object.class.equals(method.getDeclaringClass())) {

return method.invoke(this, args);

} else if (isDefaultMethod(method)) {

return invokeDefaultMethod(proxy, method, args);

}

} catch (Throwable t) {

throw ExceptionUtil.unwrapThrowable(t);

}

//缓存method封装类:MapperMethod

final MapperMethod mapperMethod = cachedMapperMethod(method);

return mapperMethod.execute(sqlSession, args);

}

//缓存MapperMethod:包含Mapper接口、methon、mybatis环境配置

private MapperMethod cachedMapperMethod(Method method) {

return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));

}

4. Mapper执行业务逻辑

案例代码:studentMapper.findStudentById(id);

分析:底层逻辑交由JDK动态代理对象执行,本质执行位置:org.apache.ibatis.binding.MapperProxy.invoke

代码:mapperMethod.execute(sqlSession, args);

org.apache.ibatis.binding.MapperMethod.execute

public Object execute(SqlSession sqlSession, Object[] args) {

Object result;

switch (command.getType()) {

// sql insert 操作,对应 mapper.xml insert标签

case INSERT: {

Object param = method.convertArgsToSqlCommandParam(args);

result = rowCountResult(sqlSession.insert(command.getName(), param));

break;

}

// sql update操作:对应mapper.xml update标签

case UPDATE: {

Object param = method.convertArgsToSqlCommandParam(args);

result = rowCountResult(sqlSession.update(command.getName(), param));

break;

}

// sql delete 操作,对应mapper.xml delete标签

case DELETE: {

Object param = method.convertArgsToSqlCommandParam(args);

result = rowCountResult(sqlSession.delete(command.getName(), param));

break;

}

// sql select 操作,对应mapper.xml select标签

case SELECT:

// 根据返回值进行判断,进行对象的操作

// 没有返回值,直接返回NULL

if (method.returnsVoid() && method.hasResultHandler()) {

executeWithResultHandler(sqlSession, args);

result = null;

// 返回值为Collection或Array

} else if (method.returnsMany()) {

result = executeForMany(sqlSession, args);

//返回值为Map

} else if (method.returnsMap()) {

result = executeForMap(sqlSession, args);

// 返回值为游标

} else if (method.returnsCursor()) {

result = executeForCursor(sqlSession, args);

// 其他默认处理: 案例属于这一种

} else {

Object param = method.convertArgsToSqlCommandParam(args);

result = sqlSession.selectOne(command.getName(), param);

if (method.returnsOptional() &&

(result == null || !method.getReturnType().equals(result.getClass()))) {

result = Optional.ofNullable(result);

}

}

break;

// flush 操作: Mapper方法注解:@Flush,刷新Statement,释放数据库资源

case FLUSH:

result = sqlSession.flushStatements();

break;

default:

throw new BindingException("Unknown execution method for: " + command.getName());

}

if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {

throw new BindingException("Mapper method "" + command.getName()

+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");

}

return result;

}

4.1 sqlSession执行数据库逻辑

案例代码: result = sqlSession.selectOne(command.getName(), param);

源码:org.apache.ibatis.session.defaults.DefaultSqlSession.selectList

  • RowBounds: mybatis 查询默认分页逻辑:0 ~ Integer.MAX_VALUE(2147483648, int存在符号位,只有31位标识数值:2^31-1)

@Override

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {

try {

//从configuration缓存获取MappedStatement: statement(sql唯一标识): com.zhiwei.advanced.mapper.StudentMapper.findStudentById

MappedStatement ms = configuration.getMappedStatement(statement);

// 底层实际逻辑交给executor执行器处理,这里executor是CachingExecutor,因为默认开启二级缓存,sqlSession创建时自动创建,里面包装SimpleExecutor对象(装饰器模式),补充缓存功能

return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);

} catch (Exception e) {

throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);

} finally {

ErrorContext.instance().reset();

}

}

//请求参数封装类:如果请求参数是collection或array,则将参数存放到Map返回,若为原生对象则直接返回

private Object wrapCollection(final Object object) {

if (object instanceof Collection) {

StrictMap<Object> map = new StrictMap<>();

map.put("collection", object);

if (object instanceof List) {

map.put("list", object);

}

return map;

} else if (object != null && object.getClass().isArray()) {

StrictMap<Object> map = new StrictMap<>();

map.put("array", object);

return map;

}

return object;

}

4.2 CachingExecutor query代码(mybatis二级缓存)

源码:org.apache.ibatis.executor.CachingExecutor.query

@Override

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)

throws SQLException {

//MappedStatement获取二级缓存:通过Configuration.cacheEnabled + cache/cache-ref 标签开启,注意缓存真实数据保存在MappedStatement自身,

// MappedStatement维护在Configuration内部从而实现相同Mapper不同session的缓存共享(二级缓存)

// cache-ref: 引用其他MappedStatement缓存,可理解为跨Mapper级别的二级缓存

Cache cache = ms.getCache();

if (cache != null) {

//MappedStatement指定flushCache=true,则强制清理缓存,相当于每次访问都清空缓存

flushCacheIfRequired(ms);

if (ms.isUseCache() && resultHandler == null) {

ensureNoOutParams(ms, boundSql);

@SuppressWarnings("unchecked")

// sqlSession内部事务缓存获取,若存则直接返回,否则交给委托Executor执行:SimpleExecutor,并将结果存入二级缓存(相同Session)

List<E> list = (List<E>) tcm.getObject(cache, key);

if (list == null) {

// 缓存不存在直接委托给SimpleExecutor执行

list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

tcm.putObject(cache, key, list); // issue #578 and #116

}

return list;

}

}

// 全局开启二级缓存,但是Mapper.xml没有开启二级缓存则默认二级缓存无效,直接委托给SimpleExecutor执行

return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

}

4.3 SimpleExecutor执行逻辑(mybatis一级缓存:localCache)

源码:org.apache.ibatis.executor.BaseExecutor.query

@Override

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {

ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());

if (closed) {

throw new ExecutorException("Executor was closed.");

}

//第一次查询或所有查询操作都完成并且mappedStatement flushCache配置true,强制清空本地缓存(一级缓存Session级别)

if (queryStack == 0 && ms.isFlushCacheRequired()) {

clearLocalCache();

}

List<E> list;

try {

queryStack++;

// mybatis一级缓存获取结果集,存在则直接缓存,否则执行对应的查询逻辑

list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;

if (list != null) {

handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);

} else {

// 具体数据库业务逻辑操作

list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);

}

} finally {

queryStack--;

}

// 第一次查询或所有查询操作都完成,进一步处理

if (queryStack == 0) {

for (DeferredLoad deferredLoad : deferredLoads) {

deferredLoad.load();

}

// issue #601

deferredLoads.clear();

//一级缓存细分的缓存作用域:默认 Configuration.localCacheScope(Session),可自定义为STATEMENT缓存

if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {

// issue #482

clearLocalCache();

}

}

return list;

}

4.4 数据库业务底层处理

接口:org.apache.ibatis.executor.BaseExecutor.queryFromDatabase

private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {

List<E> list;

// 一级缓存数据更新,存放正在处理的标志EXECUTION_PLACEHOLDER, 标识缓存正在处理,缓存对外不能提供服务,不能加载

localCache.putObject(key, EXECUTION_PLACEHOLDER);

try {

// 数据库底层操作

list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);

} finally {

// 清理本地缓存

localCache.removeObject(key);

}

//更新本地缓存

localCache.putObject(key, list);

// 存储过程参数缓存

if (ms.getStatementType() == StatementType.CALLABLE) {

localOutputParameterCache.putObject(key, parameter);

}

return list;

}

4.5 数据库数据查询

接口:org.apache.ibatis.executor.SimpleExecutor.doQuery

@Override

public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {

Statement stmt = null;

try {

Configuration configuration = ms.getConfiguration();

// 构造 StatementHandler, 主要用于生成JDBC的PrepreStatement(预编译解决SQL注入问题)

StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

stmt = prepareStatement(handler, ms.getStatementLog());

return handler.query(stmt, resultHandler);

} finally {

closeStatement(stmt);

}

}

4.5.1 StatementHandler 构造逻辑

接口:org.apache.ibatis.session.Configuration.newStatementHandler

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

//构造RoutingStatementHandler:本质是StatementHandler的装饰器,根据statementType构造不同的StatementHandler,案例 statementType为PREPARED, 对应PreparedStatementHandler

StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);

//mybatis 拦截器处理(责任链模式):StatementHandler

statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);

return statementHandler;

}

4.5.2 StatementHandler构造Statement(JDBC规范)

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {

Statement stmt;

//transaction获取数据库连接:transaction(JdbcTransaction)

Connection connection = getConnection(statementLog);

// 获取 Statement

stmt = handler.prepare(connection, transaction.getTimeout());

handler.parameterize(stmt);

return stmt;

}

org.apache.ibatis.executor.statement.BaseStatementHandler.prepare:

@Override

public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {

ErrorContext.instance().sql(boundSql.getSql());

Statement statement = null;

try {

// 初始化Statement

statement = instantiateStatement(connection);

// 设置查询和事务超时事件

setStatementTimeout(statement, transactionTimeout);

// 设置拉取数据量

setFetchSize(statement);

return statement;

} catch (SQLException e) {

closeStatement(statement);

throw e;

} catch (Exception e) {

closeStatement(statement);

throw new ExecutorException("Error preparing statement. Cause: " + e, e);

}

}

org.apache.ibatis.executor.statement.PreparedStatementHandler.instantiateStatement

// Statement初始化,本质遵循JDBC操作规范

@Override

protected Statement instantiateStatement(Connection connection) throws SQLException {

String sql = boundSql.getSql();

//如果设置主键自动生成策略:Jdbc3KeyGenerator

if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {

String[] keyColumnNames = mappedStatement.getKeyColumns();

if (keyColumnNames == null) {

return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);

} else {

return connection.prepareStatement(sql, keyColumnNames);

}

//结果集类型: 默认类型

} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {

return connection.prepareStatement(sql);

//其他类型

} else {

return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);

}

}

4.5.3 Statement参数化处理

案例:handler.parameterize(stmt);

底层源码:org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters

public void setParameters(PreparedStatement ps) {

ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());

// 解析请求参数映射

List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

if (parameterMappings != null) {

for (int i = 0; i < parameterMappings.size(); i++) {

ParameterMapping parameterMapping = parameterMappings.get(i);

//请求参数映射模式,默认为ParameterMode.IN

if (parameterMapping.getMode() != ParameterMode.OUT) {

Object value; // 具体的请求参数的值

String propertyName = parameterMapping.getProperty();

//boundSql若boundSql有相同附加参数,直接赋值

if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params

value = boundSql.getAdditionalParameter(propertyName);

//请求参数对象为空则直接返回null

} else if (parameterObject == null) {

value = null;

// 类型处理器是否包含指定请求参数类型,如果包含直接返回,原生支持(这里SID为Integer类型,直接支持)

} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {

value = parameterObject;

// 其他类型:直接从请求参数对象通过反射机制获取值

} else {

MetaObject metaObject = configuration.newMetaObject(parameterObject);

value = metaObject.getValue(propertyName);

}

// 获取请求参数映射的请求处理器

TypeHandler typeHandler = parameterMapping.getTypeHandler();

JdbcType jdbcType = parameterMapping.getJdbcType();

if (value == null && jdbcType == null) {

jdbcType = configuration.getJdbcTypeForNull();

}

try {

// JDBC规范:prepareStatement参数赋值,类似如 select *from student where sid = ?, "?"为复制的地方,赋值完成后等价于sql=select *from student where sid = "xxx"

typeHandler.setParameter(ps, i + 1, value, jdbcType);

} catch (TypeException e) {

throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);

} catch (SQLException e) {

throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);

}

}

}

}

}

4.5.4 执行SQL查询

案例代码:handler.query(stmt, resultHandler);

源码:org.apache.ibatis.executor.statement.PreparedStatementHandler.query

@Override

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {

PreparedStatement ps = (PreparedStatement) statement;

//执行prepareStatment

ps.execute();

//resultSetHandler处理查询操作后的结果集

return resultSetHandler.handleResultSets(ps);

}

4.5.5 SQL查询结果集处理resultSetHandler

接口:org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets

@Override

public List<Object> handleResultSets(Statement stmt) throws SQLException {

ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

final List<Object> multipleResults = new ArrayList<>();

int resultSetCount = 0;

//构建ResultSetWrapper(构造函数), 本质获取数据库表字段元数据,方便后续结果集封装

ResultSetWrapper rsw = getFirstResultSet(stmt);

// 获取ResultMap

List<ResultMap> resultMaps = mappedStatement.getResultMaps();

int resultMapCount = resultMaps.size();

validateResultMapsCount(rsw, resultMapCount);

while (rsw != null && resultMapCount > resultSetCount) {

ResultMap resultMap = resultMaps.get(resultSetCount);

// 数据库记录解析:ResultSetHandler解析解析为实体对象,对象保存在multipleResults集合

handleResultSet(rsw, resultMap, multipleResults, null);

rsw = getNextResultSet(stmt);

cleanUpAfterHandlingResultSet();

resultSetCount++;

}

// resultSets 默认为空,不进入处理

String[] resultSets = mappedStatement.getResultSets();

if (resultSets != null) {

while (rsw != null && resultSetCount < resultSets.length) {

ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);

if (parentMapping != null) {

String nestedResultMapId = parentMapping.getNestedResultMapId();

ResultMap resultMap = configuration.getResultMap(nestedResultMapId);

handleResultSet(rsw, resultMap, null, parentMapping);

}

rsw = getNextResultSet(stmt);

cleanUpAfterHandlingResultSet();

resultSetCount++;

}

}

//返回结果

return collapseSingleResultList(multipleResults);

}

.......................... mybatis 整个工作流程梳理完成 ..............................

以上是 【mybatis】mybatis工作原理底层源码全流程解析 的全部内容, 来源链接: utcz.com/z/534456.html

回到顶部