org.apache.ibatis.session.SqlSession
是 mybatis 操做sql、 获取mapper、处理事务的基本单元。通常意义上咱们运用mybatis 都是在操做 sqlSessionsql
类图以下:apache
org.apache.ibatis.session.defaults.DefaultSqlSession
默认实现。session
DefaultSqlSession
的初始化过程 SqlSessionFactoryBuilder
--> DefaultSqlSessionFactory
--> SqlSession
全部 <T> T selectOne
、<E> List<E> selectList
均由<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds)
实现。源码:数据结构
[@Override](https://my.oschina.net/u/1162528) public <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(); } }
源码分析: 该方法接受 3个参数
- statement
sql语句的标识符,就是经常使用的 namespace.sqlId
组合,具备惟一性mybatis
经过此id 能够从mybatis配置类org.apache.ibatis.session.Configuration
中获取 映射语句对象MappedStatement
, id 跟语句的映射关系储存在 Configuration
下的内部数据结构(hashmap 字类) Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
中 - parameter
顾名思义 要传递给statement
标识的sql语句的参数对象 - org.apache.ibatis.session.RowBounds
限制对象检索的界限。比方说 上面2个参数联合查出来200条,rowBounds
的offset
和limit
造成一个区间 [20,150]
,截取在此区间的数据集。就是mybatis 逻辑分页 由 org.apache.ibatis.executor.Executor
操做返回查询结果app
[@Override](https://my.oschina.net/u/1162528) public int update(String statement, Object parameter) { try { dirty = true; MappedStatement ms = configuration.getMappedStatement(statement); return executor.update(ms, wrapCollection(parameter)); } catch (Exception e) { throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
sqlSession 操做mapper 接口分析ide
public <T> T getMapper(Class<T> type)
的底层方法为 Configuration.<T>getMapper(type, this)
,也就是说获取Mapper接口是由配置类来完成的,具体是由其持有的 MapperRegistry
来维护。源码分析
MapperRegistry
中的成员 Map<Class<?>, MapperProxyFactory<?>> knownMappers
是Mapper 接口的注册表,全部注册的Mapper 将与之对应的MapperProxyFactory
存储在该注册表中。底层是经过JDK 代理来进行代理ui
咱们的业务接口经过MapperProxy
代理,代理对象经过MapperMethod
执行方法this
[@Override](https://my.oschina.net/u/1162528) 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); } // 若是是抽象 没有实现构造 方法的代理 final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); }
流程以下:
注册Mapper
在分析了如何获取Mapper以后,再搞一搞如何注册Mapper,经过上面知道Mapper的获取是Configuration
委托 MapperRegistry
获取,一样的流程,提供了三种方式来注册
// 将指定包下面的指定接口进行加载 public void addMappers(String packageName, Class<?> superType) { mapperRegistry.addMappers(packageName, superType); } //加载指定包下面的全部接口 public void addMappers(String packageName) { mapperRegistry.addMappers(packageName); } //加载指定的接口 public <T> void addMapper(Class<T> type) { mapperRegistry.addMapper(type); }
核心基于MapperRegistry
下的方法:
public <T> void addMapper(Class<T> type) { // 类型必须是接口 if (type.isInterface()) { // 必须是未注册的 if (hasMapper(type)) { throw new BindingException("Type " + type + " is already known to the MapperRegistry."); } // 加载完成标记 boolean loadCompleted = false; try { knownMappers.put(type, new MapperProxyFactory<T>(type)); // It's important that the type is added before the parser is run // otherwise the binding may automatically be attempted by the // mapper parser. If the type is already known, it won't try. //经过MapperAnnotationBuilder来对xml或者类进行解析 MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse(); loadCompleted = true; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } }
批量注册某个包下基于某个超类的 是对上面进行循环遍历进行
/** * @since 3.2.2 */ public void addMappers(String packageName, Class<?> superType) { ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>(); // 判断包下是否有该超类的实现 没有会抛出异常 主要起到检测加载做用 resolverUtil.find(new ResolverUtil.IsA(superType), packageName); // 获取清单并进行注册 Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses(); for (Class<?> mapperClass : mapperSet) { addMapper(mapperClass); } }
注册包下全部的接口
/** * @since 3.2.2 */ public void addMappers(String packageName) { addMappers(packageName, Object.class); }
由上面发现 重点是 MapperAnnotationBuilder
,该类也十分重要的转换类,后面会继续分析