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
,該類也十分重要的轉換類,後面會繼續分析