查询举例

public class Main {public static void main(String[] args) throws IOException {String resource = "mybatis.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();try {ProductMapper productMapper = sqlSession.getMapper(ProductMapper.class);List<Product> productList = productMapper.selectProductList();for (Product product : productList) {System.out.printf(product.toString());}} finally {sqlSession.close();}}
}

MyBatis核心构件

名称 作用
SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合
ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数
ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换
MappedStatement MappedStatement维护了一条select
SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
BoundSql 表示动态生成的SQL语句以及相应的参数信息
Configuration MyBatis所有的配置信息都维持在Configuration对象之中

SqlSessionFactory创建session

DefaultSqlSessionFactory

  @Overridepublic SqlSession openSession() {return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);}private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {final Environment environment = configuration.getEnvironment();final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);final Executor executor = configuration.newExecutor(tx, execType);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();}}

创建事务,简单执行器,执行器添加拦截器链,返回DefaultSqlSession

DefaultSqlSession获取mapper代理

@Overridepublic <T> T getMapper(Class<T> type) {return configuration.<T>getMapper(type, this);}

Configuration

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {return mapperRegistry.getMapper(type, sqlSession);}

MapperRegistry

  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 {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);}}

MapperProxyFactory生成接口类的动态代理,MapperProxy继承InvocationHandler增强方法

  public T newInstance(SqlSession sqlSession) {final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);return newInstance(mapperProxy);}@SuppressWarnings("unchecked")protected T newInstance(MapperProxy<T> mapperProxy) {return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);}

MapperProxy

public class MapperProxy<T> implements InvocationHandler, Serializable {@Overridepublic 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);}final MapperMethod mapperMethod = cachedMapperMethod(method);return mapperMethod.execute(sqlSession, args);}private MapperMethod cachedMapperMethod(Method method) {MapperMethod mapperMethod = methodCache.get(method);if (mapperMethod == null) {mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());methodCache.put(method, mapperMethod);}return mapperMethod;}

MapperMethod执行代理方法,分局增删改查分类调用SqlSession的方法

public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;}case UPDATE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.update(command.getName(), param));break;}case DELETE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.delete(command.getName(), param));break;}case SELECT:if (method.returnsVoid() && method.hasResultHandler()) {executeWithResultHandler(sqlSession, args);result = null;} else if (method.returnsMany()) {result = executeForMany(sqlSession, args);} 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);}break;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;}

DefaultSqlSession查询单个selectOne,调用selectList方法,调用执行器查询

@Overridepublic <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) {return list.get(0);} else if (list.size() > 1) {throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());} else {return null;}}@Overridepublic <E> List<E> selectList(String statement, Object parameter) {return this.selectList(statement, parameter, RowBounds.DEFAULT);}@Overridepublic <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {try {MappedStatement ms = configuration.getMappedStatement(statement);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();}}

Configuration获取MappedStatement,先创建所有的MappedStatement,再拿出需要的

  public MappedStatement getMappedStatement(String id) {return this.getMappedStatement(id, true);}public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {if (validateIncompleteStatements) {buildAllStatements();}return mappedStatements.get(id);}/** Parses all the unprocessed statement nodes in the cache. It is recommended* to call this method once all the mappers are added as it provides fail-fast* statement validation.*/protected void buildAllStatements() {if (!incompleteResultMaps.isEmpty()) {synchronized (incompleteResultMaps) {// This always throws a BuilderException.incompleteResultMaps.iterator().next().resolve();}}if (!incompleteCacheRefs.isEmpty()) {synchronized (incompleteCacheRefs) {// This always throws a BuilderException.incompleteCacheRefs.iterator().next().resolveCacheRef();}}if (!incompleteStatements.isEmpty()) {synchronized (incompleteStatements) {// This always throws a BuilderException.incompleteStatements.iterator().next().parseStatementNode();}}if (!incompleteMethods.isEmpty()) {synchronized (incompleteMethods) {// This always throws a BuilderException.incompleteMethods.iterator().next().resolve();}}}

BaseExecutor创建缓存key,先到缓存中查询,如果有直接返回,否则到数据库查询,存到缓存中

@Overridepublic <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {BoundSql boundSql = ms.getBoundSql(parameter);CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);return query(ms, parameter, rowBounds, resultHandler, key, boundSql);}@Overridepublic CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {if (closed) {throw new ExecutorException("Executor was closed.");}CacheKey cacheKey = new CacheKey();cacheKey.update(ms.getId());cacheKey.update(rowBounds.getOffset());cacheKey.update(rowBounds.getLimit());cacheKey.update(boundSql.getSql());List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();// mimic DefaultParameterHandler logicfor (ParameterMapping parameterMapping : parameterMappings) {if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) {value = boundSql.getAdditionalParameter(propertyName);} else if (parameterObject == null) {value = null;} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else {MetaObject metaObject = configuration.newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}cacheKey.update(value);}}if (configuration.getEnvironment() != null) {// issue #176cacheKey.update(configuration.getEnvironment().getId());}return cacheKey;}@SuppressWarnings("unchecked")@Overridepublic <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.");}if (queryStack == 0 && ms.isFlushCacheRequired()) {clearLocalCache();}List<E> list;try {queryStack++;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 #601deferredLoads.clear();if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {// issue #482clearLocalCache();}}return list;}//缓存中查询private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) {if (ms.getStatementType() == StatementType.CALLABLE) {final Object cachedParameter = localOutputParameterCache.getObject(key);if (cachedParameter != null && parameter != null) {final MetaObject metaCachedParameter = configuration.newMetaObject(cachedParameter);final MetaObject metaParameter = configuration.newMetaObject(parameter);for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {if (parameterMapping.getMode() != ParameterMode.IN) {final String parameterName = parameterMapping.getProperty();final Object cachedValue = metaCachedParameter.getValue(parameterName);metaParameter.setValue(parameterName, cachedValue);}}}}}//从数据库查询,然后放入缓存中private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {List<E> list;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;}

SimpleExecutor查询数据库

@Overridepublic <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 handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);stmt = prepareStatement(handler, ms.getStatementLog());return handler.<E>query(stmt, resultHandler);} finally {closeStatement(stmt);}}

SimpleStatementHandler查询,封装结果集

@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {String sql = boundSql.getSql();statement.execute(sql);return resultSetHandler.<E>handleResultSets(statement);}

DefaultResultSetHandler封装结果集

  @Overridepublic List<Object> handleResultSets(Statement stmt) throws SQLException {ErrorContext.instance().activity("handling results").object(mappedStatement.getId());final List<Object> multipleResults = new ArrayList<Object>();int resultSetCount = 0;ResultSetWrapper rsw = getFirstResultSet(stmt);List<ResultMap> resultMaps = mappedStatement.getResultMaps();int resultMapCount = resultMaps.size();validateResultMapsCount(rsw, resultMapCount);while (rsw != null && resultMapCount > resultSetCount) {ResultMap resultMap = resultMaps.get(resultSetCount);handleResultSet(rsw, resultMap, multipleResults, null);rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}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);}@SuppressWarnings("unchecked")private List<Object> collapseSingleResultList(List<Object> multipleResults) {return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;}

mybatis3源码2-查询相关推荐

  1. MyBatis3源码解析(5)查询结果处理

    简介 上篇中解析了MyBatis3中参数是如何传递处理的,本篇接着看看在获取到查询结果后,MyBatis3是如何将SQL查询结果与我们接口函数定义的返回结果对应的 源码 获取结果后处理的入口 在:My ...

  2. MyBatis3源码解析(3)查询语句执行

    简介 上篇探索了MyBatis中如何获取数据库连接,本篇继续探索,来看看MyBatis中如何执行一条查询语句 测试代码 本篇文中用于调试的测试代码请参考:MyBatis3源码解析(1)探索准备 完整的 ...

  3. Mybatis3 源码解析系列

    简介 Mybatis作为一个优秀的Java持久化框架,在我们的日常工作中相信都会用到,本次源码解析系列,就开始探索下Mybatis 总结 在MyBatis的学习中,首先通读了<MyBatis3源 ...

  4. MyBatis3源码解析(6)TypeHandler使用

    简介 在上几篇中,介绍了MyBatis3对参数和结果的解析转换,对于常规数据类型,默认的处理已经足够应付了,但日常开发中会有一些特殊的类型,就可以通过TypeHandler来进行处理 示例准备 本篇文 ...

  5. Mybatis3源码分析(05)-加载Configuration-加载MappedStatement

    2019独角兽企业重金招聘Python工程师标准>>> Mybatis3源码分析(05)-加载Configuration-加载MappedStatement 博客分类: java m ...

  6. MyBatis3源码解析(2)数据库连接

    简介 基于上篇的示例感受,下面我们探索下MyBatis连接数据库的细节是如果实现的,在日常使用中是如何能和Druid数据库连接池等配合起来的 源码解析 基于上篇的示例代码: public class ...

  7. 2022-10-24 ClickHouse 源码解析-查询引擎经典理论

    ClickHouse 源码解析: 综述 ClickHouse 源码解析: MergeTree Write-Path ClickHouse 源码解析: MergeTree Read-Path Click ...

  8. MyBatis3源码解析(4)参数解析

    简介 上篇文章中探索了查询语句的执行过程,下面我们接着来看看其中的查询参数的解析细节,是如何工作的 参数的解析 在日常的开发中,常见的参数有如下几种: 1.直接传入: func(Object para ...

  9. MyBatis3源码解析(1)探索准备

    简介 本篇文章将使用原生的JDBC方式操作数据库,然后在使用Mybatis提供的方式操作数据库,通过对比两部分的操作,大致得到Mybatis所做的主要工作,为接下来的源码解析做准备 示例代码 完整的工 ...

  10. MyBatis3源码解析(8)MyBatis与Spring的结合

    简介 在上几篇文章中,解析了MyBatis的核心原理部分,我们大致对其有了一定的了解,接下来我们看看在日常的开发中MyBatis是如何与Spring框架结合的 源码解析 在我们的日常开发中,使用Spr ...

最新文章

  1. lamp mysql大小限制_[转]LAMP 系统性能调优,第 3 部分: MySQL 服务器调优
  2. tomcat 反代配置
  3. python查找指定字符串并替换_python 查找字符串并将其替换
  4. linux rc4,Linux kernel 4.8-rc4发布下载,正式版越来越近
  5. php 微信时间戳转换工具,微信小程序时间戳转换
  6. Aps.Net js ymPrompt消息提示组件4.0版
  7. 【软件工程】层次图、HIPO图——期末快速复习用
  8. gdal工具(一)矢量栅格化工具 gdal_rasterize
  9. 【HTML期末学生大作业】 制作一个简单HTML保护野生动物老虎网页设计专题(HTML+CSS)
  10. Excel VBA 免密查看VBE加密代码
  11. 微信美团服务器开小差,“美团无法使用微信支付”耽误大家干饭,客服:异常已经解决...
  12. 损失函数——KL散度(Kullback-Leibler Divergence,KL Divergence)
  13. BookReader
  14. Google针对非 SDK 接口的限制
  15. linux之Centos6升级至centos7
  16. 损失函数与准确率的关系
  17. 将Chrome作为不限速下载器使用
  18. (四)Gluster 配置
  19. 绿色 fiddler 免安装 抓包工具
  20. Spark 定制版:002~Spark Streaming(二)

热门文章

  1. 【零基础学Java】—递归(五十一)
  2. 【Express】—Express路由请求
  3. 计算机图形学 实现鼠标拖拽图元
  4. 刚来公司时我却做了一件最傻的事
  5. TrashFlash卡是什么
  6. 没有文化适合自媒体创业吗
  7. 今天和朋友去参观一家做电商创业公司
  8. 互联网的大厂就那么几家,所以很多员工跳槽后都是互相流动的
  9. 程序员未来会成为非常内卷式的职业吗?
  10. Qt4_内置的窗口部件类和对话框类