ibatis访问数据库的大致逻辑
/** * Builds an SqlMapClient using the specified reader.根据xml文件输入流 创建一个client对象 * @param reader A Reader instance that reads an sql- map-config.xml file. * The reader should read an well formed sql- map-config.xml file. * @return An SqlMapClient instance. */ public static SqlMapClient buildSqlMapClient(Reader reader) {// return new XmlSqlMapClientBuilder().buildSqlMap(reader); return new SqlMapConfigParser().parse(reader); }???2.接着往下看?SqlMapClient?com.ibatis.sqlmap.engine.builder.xml.SqlMapConfigParser.parse(Reader?reader)
public SqlMapClient parse(Reader reader) { try { if ( vars.sqlMapConfigConv != null) { reader = vars.sqlMapConfigConv .convertXml(reader); } parser.parse(reader); return vars.client ; } catch (Exception e) { throw new NestedRuntimeException("Error occurred. Cause: " + e, e); } }??这里xml文件的输入流被用来转换sql去了?但是这个方法返回的client并不是直接从这个方法生成的?我们看
public class SqlMapConfigParser extends BaseParser { public SqlMapConfigParser(XmlConverter sqlMapConfigConv, XmlConverter sqlMapConv) { super( new Variables()); parser.setValidation( true); parser.setEntityResolver( new SqlMapClasspathEntityResolver()); vars.sqlMapConfigConv = sqlMapConfigConv; vars.sqlMapConv = sqlMapConv; vars.delegate = new SqlMapExecutorDelegate();//直接new了一个 vars.typeHandlerFactory = vars.delegate .getTypeHandlerFactory(); vars.client = new SqlMapClientImpl(vars .delegate ); registerDefaultTypeAliases(); addSqlMapConfigNodelets(); addGlobalPropNodelets(); addSettingsNodelets(); addTypeAliasNodelets(); addTypeHandlerNodelets(); addTransactionManagerNodelets(); addSqlMapNodelets(); }}?发现SqlMapConfigParser?这个类的构造方法里就有vars.?delegate?=?new?SqlMapExecutorDelegate();//直接new了一个vars.?client?=?new?SqlMapClientImpl(vars?.delegate?);?这两行,生产了client对象 ?至于具体流程 这里不去追究 只需要知道大致是这样就得到了client对象?????用client对象访问CRUD方法,来访问数据库?List<User>?list?=?sqlMap.queryForList("getAllUsers");??这里的client是?SqlMapClientImpl对象这个类包括了所有CRUD方法,?SqlMapClientImpl 实现了ExtendedSqlMapClient接口?ExtendedSqlMapClient接口又继承了SqlMapClient接口?SqlMapClient接口继承了SqlMapExecutor, SqlMapTransactionManager两个接口?SqlMapExecutor, SqlMapTransactionManager这两个接口分别让client获得了CRUD方法和事务控制的能力??有一个图可以简明的表达这个关系:???我们来看SqlMapClientImpl?里面CRUD方法的代码:?
public class SqlMapClientImpl implements ExtendedSqlMapClient { public SqlMapExecutorDelegate delegate; private ThreadLocal localSqlMapSession = new ThreadLocal (); public Object queryForObject(String id, Object paramObject, Object resultObject) throws SQLException { return getLocalSqlMapSession().queryForObject(id, paramObject, resultObject); } private SqlMapSessionImpl getLocalSqlMapSession() { SqlMapSessionImpl sqlMapSession = (SqlMapSessionImpl) localSqlMapSession.get(); if (sqlMapSession == null || sqlMapSession.isClosed()) { sqlMapSession = new SqlMapSessionImpl(this); localSqlMapSession.set(sqlMapSession); } return sqlMapSession; }}?以queryForObject为例,是获取了SqlMapSessionImpl?对象,然后执行SqlMapSessionImpl?对象里面的queryForObject方法的??我们再来看SqlMapSessionImpl??
public class SqlMapSessionImpl implements SqlMapSession { protected SqlMapExecutorDelegate delegate; protected SessionScope session; protected boolean closed ; public Object queryForObject(String id, Object paramObject, Object resultObject) throws SQLException { return delegate.queryForObject(session , id, paramObject, resultObject); }}??可以发现?SqlMapSessionImpl?实现了SqlMapSession?接口这个对象有SqlMapExecutorDelegate?CRUD操作代理类对象SessionScope? 对象 里面存了执行数据库操作所需的各种资源和对象(会话)queryForObject方法的实现是通过代理类SqlMapExecutorDelegate?的方法queryForObject??看SqlMapExecutorDelegate?的源码?
/** * Execute a select for a single object * * @param session - the session scope * @param id - the statement ID * @param paramObject - the parameter object * @param resultObject - the result object (if not supplied or null, a new object will be created) * @return - the result of the query * @throws SQLException - if the query fails */ public Object queryForObject(SessionScope session, String id, Object paramObject, Object resultObject) throws SQLException { Object object = null; MappedStatement ms = getMappedStatement(id); Transaction trans = getTransaction(session); boolean autoStart = trans == null; try { trans = autoStartTransaction(session, autoStart, trans); RequestScope request = popRequest(session, ms); try { object = ms.executeQueryForObject(request, trans, paramObject, resultObject); } finally { pushRequest(request); } autoCommitTransaction(session, autoStart); } finally { autoEndTransaction(session, autoStart); } return object; }??首先?MappedStatement ms = getMappedStatement(id); 根据sqlMap里的id 获取到SQL语句对象Transaction trans = getTransaction(session); 从session中获取Transaction事务管理对象?然后RequestScope request = popRequest(session, ms); 从request池中取出request对象?object = ms.executeQueryForObject(request, trans, paramObject, resultObject);执行查询?pushRequest(request);放回request池?autoCommitTransaction(session, autoStart);提交事务??return?object;返回查询结果??????其中?ms.executeQueryForObject(request, trans, paramObject, resultObject);往下看发现其实是GeneralStatement类继承了BaseStatementBaseStatement又实现了MappedStatement?接口?所以这里MappedStatement ms = getMappedStatement(id); 得到的是GeneralStatement实例??
public Object executeQueryForObject(RequestScope request, Transaction trans, Object parameterObject, Object resultObject) throws SQLException { try { Object object = null; DefaultRowHandler rowHandler = new DefaultRowHandler(); executeQueryWithCallback(request, trans.getConnection(), parameterObject, resultObject, rowHandler, SqlExecutor.NO_SKIPPED_RESULTS , SqlExecutor.NO_MAXIMUM_RESULTS); List list = rowHandler.getList(); if (list.size() > 1) { throw new SQLException("Error: executeQueryForObject returned too many results."); } else if (list.size() > 0) { object = list.get(0); } return object; } catch (TransactionException e) { throw new NestedSQLException("Error getting Connection from Transaction. Cause: " + e, e); } }??这里可以看到 new 了一个rowHandler?对象 ?然后执行executeQueryWithCallback?方法?然后从rowHandler?对象里获取到结果集list?取list里的第一个元素返回???其中DefaultRowHandler?类也很简单 里面就是一个list?
public class DefaultRowHandler implements RowHandler { private List list = new ArrayList(); public void handleRow(Object valueObject) { list.add(valueObject) ; } public List getList() { return list; }}???再看executeQueryWithCallback 方法的实现?ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback()?
protected void executeQueryWithCallback(RequestScope request, Connection conn, Object parameterObject, Object resultObject, RowHandler rowHandler, int skipResults, int maxResults) throws SQLException { ErrorContext errorContext = request.getErrorContext(); errorContext .setActivity("preparing the mapped statement for execution"); errorContext .setObjectId(this.getId()); errorContext .setResource(this.getResource()); try { parameterObject = validateParameter(parameterObject); Sql sql = getSql(); errorContext .setMoreInfo("Check the parameter map." ); ParameterMap parameterMap = sql.getParameterMap(request, parameterObject); errorContext .setMoreInfo("Check the result map." ); ResultMap resultMap = sql.getResultMap(request, parameterObject); request.setResultMap(resultMap); request.setParameterMap(parameterMap); errorContext .setMoreInfo("Check the parameter map." ); Object[] parameters = parameterMap.getParameterObjectValues(request, parameterObject); errorContext .setMoreInfo("Check the SQL statement." ); String sqlString = sql.getSql(request, parameterObject);//这个就是拼接SQL的方法 errorContext .setActivity("executing mapped statement" ); errorContext .setMoreInfo("Check the SQL statement or the result map."); RowHandlerCallback callback = new RowHandlerCallback(resultMap, resultObject, rowHandler); sqlExecuteQuery(request, conn, sqlString, parameters, skipResults, maxResults, callback); //这里就是已经拼接好的sql 了 可以做个输出 System. out.println( sqlString); errorContext .setMoreInfo("Check the output parameters." ); if (parameterObject != null) { postProcessParameterObject(request, parameterObject, parameters); } errorContext .reset(); sql.cleanup(request); notifyListeners(); } catch (SQLException e) { errorContext .setCause(e); throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e); } catch (Exception e) { errorContext .setCause(e); throw new NestedSQLException(errorContext.toString(), e); } }???可以看到 获取参数Map ?和结果集Map ?ParameterMap?,ResultMap?然后是拼接sql语句String sqlString = sql.getSql(request, parameterObject);?//这个就是拼接SQL的方法??再执行sql?? ? ? RowHandlerCallback callback =?new?RowHandlerCallback(resultMap, resultObject, rowHandler);????? sqlExecuteQuery(request, conn, sqlString, parameters, skipResults, maxResults, callback);???接下来是最核心的?到了执行中最核心的一步,也是最后一步: MappedStatement.sqlExecuteQuery()方法,它负责sql的最后执行,内部调用了SqlExecutor.executeQuery()方法ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery()
protected void sqlExecuteQuery(RequestScope request, Connection conn, String sqlString, Object[] parameters, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { getSqlExecutor().executeQuery(request, conn, sqlString, parameters, skipResults, maxResults, callback); }??先获取SqlExecutor对象com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery()?
/** * Long form of the method to execute a query * * @param request - the request scope * @param conn - the database connection * @param sql - the SQL statement to execute * @param parameters - the parameters for the statement * @param skipResults - the number of results to skip * @param maxResults - the maximum number of results to return * @param callback - the row handler for the query * * @throws SQLException - if the query fails */ public void executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { ErrorContext errorContext = request.getErrorContext(); errorContext.setActivity( "executing query"); errorContext.setObjectId(sql); PreparedStatement ps = null; ResultSet rs = null; try { errorContext.setMoreInfo( "Check the SQL Statement (preparation failed)."); Integer rsType = request.getStatement().getResultSetType(); if (rsType != null) { ps = conn.prepareStatement(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY ); } else { ps = conn.prepareStatement(sql); } Integer fetchSize = request.getStatement().getFetchSize(); if (fetchSize != null) { ps.setFetchSize(fetchSize.intValue()); } errorContext.setMoreInfo( "Check the parameters (set parameters failed)."); request.getParameterMap().setParameters(request, ps, parameters); errorContext.setMoreInfo( "Check the statement (query failed)." ); ps.execute(); rs = getFirstResultSet(ps); if (rs != null) { errorContext.setMoreInfo( "Check the results (failed to retrieve results)."); handleResults(request, rs, skipResults, maxResults, callback); } // clear out remaining results while (ps.getMoreResults()); } finally { try { closeResultSet(rs); } finally { closeStatement(ps); } } }?可以发现 这是ibatis访问数据库的最后一步了 其实就是我们以前用的jdbc访问数据库的代码这一步可以得到最终拼接完成的SQL?
ps = conn.prepareStatement(sql); ps.execute(); rs = getFirstResultSet(ps);handleResults(request, rs, skipResults, maxResults, callback); rs放入callback?????????