上兩篇已經講解了SqlSessionFactory的創建和SqlSession創建過程。今天我們來分析myabtis的sql是如何一步一步走到Excutor。
還是之前的demo
public static void main(String[] args) throws Exception { SqlSessionFactory sessionFactory = null; String resource = "configuration.xml"; sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource)); SqlSession sqlSession = sessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); System.out.println(userMapper.findUserById(1)); }
我們想看下基本的時序圖有個大致了解
1:DefaultSqlSession獲取getMapper
@Override public T getMapper(Class type) { return configuration.getMapper(type, this); }
2:Configuration獲取getMapper
public T getMapper(Class type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
Configuration和DefaultSqlSession什么都沒有做,交給了MapperRegistry,我們看下MapperRegistry做了什么。
3:MapperRegistry獲取getMapper
@SuppressWarnings("unchecked") public T getMapper(Class type, SqlSession sqlSession) { final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) 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); } }
通過knownMappers獲取一個MapperProxyFactory,后然newInstance了一下,那么newInstance得到了什么東西呢?
4:MapperProxyFactory
@SuppressWarnings("unchecked") protected T newInstance(MapperProxy mapperProxy) { //java代理 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }
public T newInstance(SqlSession sqlSession) { final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); }
通過以上的動態代理,咱們就可以方便地使用dao接口啦。到這里我們還沒有看到任何執行sql有關的信息,或者說還沒走到文章開始說的的Excutor, 我們看下MapperProxy代理類
MapperProxy
public class MapperProxy implements InvocationHandler, Serializable { private static final long serialVersionUID = -6424540398559729838L; private final SqlSession sqlSession; private final Class mapperInterface; private final Map methodCache; public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache) { this.sqlSession = sqlSession; this.mapperInterface = mapperInterface; this.methodCache = methodCache; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { try { return method.invoke(this, 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.execute進行處理,到這里我們只是看到了execute字眼了,我們繼續往下看。
public Object execute(SqlSession sqlSession, Object[] args) { Object result; if (SqlCommandType.INSERT == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.insert(command.getName(), param)); } else if (SqlCommandType.UPDATE == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); } else if (SqlCommandType.DELETE == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); } else if (SqlCommandType.SELECT == command.getType()) { 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); } } else if (SqlCommandType.FLUSH == command.getType()) { result = sqlSession.flushStatements(); } else { 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; }
上面代碼先是判斷CRUD類型,然后根據類型去選擇到底執行sqlSession中的哪個方法,我們現在是查詢那么程序應該走到sqlSession.selectOne。
@Override public T selectOne(String statement, Object parameter) { // Popular vote was to return null on 0 results and throw exception on too many. List list = this.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; } }
@Override public List selectList(String statement, Object parameter, RowBounds rowBounds) { try { MappedStatement ms = configuration.getMappedStatement(statement); //終於看到我們要找的executor接口了 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(); } }
我們終於看到executor類了, 調用了query方法,接下來的事情全部交給了executor處理了,
executor底層的分析已經在上一篇已經分享了。
我們代理執行sql的基本順序是
MapperMethod.execute() --> DefaultSqlSession.selectOne --> BaseExecutor.query --> SimpleExecutor.doQuery --> SimpleStatementHandler.query --> DefaultResultSetHandler.handleResultSets(Statement stmt) 最終得到數據。