首先看一段最基本的ibatis执行代码
1 public static void main(String[] args) throws IOException, SQLException{ 2 String config = "ibatis/SqlMapConfig.xml"; 3 Reader reader = Resources.getResourceAsReader(config); 4 SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader); 5 List<Product> list = sqlMap.queryForList("getProductInfo", 1); 6 for(Product product : list){ 7 System.out.println(product); 8 } 9 }
首先使用Resources读取配置文件信息返回给reade,Resources的相关源码
1 public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException { 2 InputStream in = null; 3 if (loader != null) in = loader.getResourceAsStream(resource); 4 if (in == null) in = ClassLoader.getSystemResourceAsStream(resource); 5 if (in == null) throw new IOException("Could not find resource " + resource); 6 return in; 7 } 8 9 public static Reader getResourceAsReader(String resource) throws IOException { 10 Reader reader; 11 if (charset == null) { 12 reader = new InputStreamReader(getResourceAsStream(resource)); 13 } else { 14 reader = new InputStreamReader(getResourceAsStream(resource), charset); 15 } 16 17 return reader; 18 }
就是调用Resources的静态方法getResourceAsReader,该方法调用getResourceAsStream方法,ClassLoader根据配置文件的路径返回InputStream,找不到文件则抛出异常。getResourceAsReader方法根据返回的InputStream返回Reader,若指定了编码类型则转换为相应编码。
SqlMapClientBuilder类的buildSqlMapClient方法代码
1 public static SqlMapClient buildSqlMapClient(Reader reader) { 2 // return new XmlSqlMapClientBuilder().buildSqlMap(reader); 3 return new SqlMapConfigParser().parse(reader); 4 }
SqlMapConfigParser类根据配置文件解析参数返回
下面看一下ibatis内部SqlMapClient的实现过程。
SqlMapClientImpl的部分代码
1 public class SqlMapClientImpl implements SqlMapClient, ExtendedSqlMapClient { 2 3 private static final Log log = LogFactory.getLog(SqlMapClientImpl.class); 4 5 /** 6 * Delegate for SQL execution 7 */ 8 public SqlMapExecutorDelegate delegate; 9 10 protected ThreadLocal localSqlMapSession = new ThreadLocal(); 11 12 /** 13 * Constructor to supply a delegate 14 * 15 * @param delegate - the delegate 16 */ 17 public SqlMapClientImpl(SqlMapExecutorDelegate delegate) { 18 this.delegate = delegate; 19 } 20 21 22 protected SqlMapSessionImpl getLocalSqlMapSession() { 23 SqlMapSessionImpl sqlMapSession = (SqlMapSessionImpl) localSqlMapSession.get(); 24 if (sqlMapSession == null || sqlMapSession.isClosed()) { 25 sqlMapSession = new SqlMapSessionImpl(this); 26 localSqlMapSession.set(sqlMapSession); 27 } 28 return sqlMapSession; 29 } 30 31 public List queryForList(String id, Object paramObject) throws SQLException { 32 return getLocalSqlMapSession().queryForList(id, paramObject); 33 } 34 35 public List queryForList(String id) throws SQLException { 36 return getLocalSqlMapSession().queryForList(id); 37 } 38 39 public List queryForList(String id, Object paramObject, int skip, int max) throws SQLException { 40 return getLocalSqlMapSession().queryForList(id, paramObject, skip, max); 41 } 42 43 public List queryForList(String id, int skip, int max) throws SQLException { 44 return getLocalSqlMapSession().queryForList(id, skip, max); 45 } 46 }
由代码中看出,ThreadLocal 的localSqlMapSession中存储着SqlMapSessionImpl实例,queryForList方法实际是使用本线程内的SqlMapSessionImpl的queryForList方法。
SqlMapSessionImpl的部分代码
1 public class SqlMapSessionImpl implements SqlMapSession { 2 3 protected SqlMapExecutorDelegate delegate; 4 protected SessionScope sessionScope; 5 protected boolean closed; 6 7 /** 8 * Constructor 9 * 10 * @param client - the client that will use the session 11 */ 12 public SqlMapSessionImpl(SqlMapClientImpl client) { 13 this.delegate = client.getDelegate(); 14 this.sessionScope = this.delegate.beginSessionScope(); 15 this.sessionScope.setSqlMapClient(client); 16 this.sessionScope.setSqlMapExecutor(client); 17 this.sessionScope.setSqlMapTxMgr(client); 18 this.closed = false; 19 } 20 21 public List queryForList(String id, Object paramObject) throws SQLException { 22 return delegate.queryForList(sessionScope, id, paramObject); 23 } 24 25 public List queryForList(String id) throws SQLException { 26 return queryForList(id, null); 27 } 28 29 public List queryForList(String id, Object paramObject, int skip, int max) throws SQLException { 30 return delegate.queryForList(sessionScope, id, paramObject, skip, max); 31 } 32 33 public List queryForList(String id, int skip, int max) throws SQLException { 34 return queryForList(id, null, skip, max); 35 } 36 } 37 38
SqlMapSessionImpl中有一个delegate代理,它的queryForList方法中调用delegate的queryForList方法。
SqlMapExecutorDelegate类比较复杂,它实现了执行数据库操作的完整环境,包括缓存、MappedStatement、参数映射ParameterMap、返回结果ResultMap、事务管理、增删改成操作。源代码有900+行,只给出部分代码,完整代码参考ibatis源码包中SqlMapExecutorDelegate.java文件。
1 public class SqlMapExecutorDelegate { 2 3 private static final Probe PROBE = ProbeFactory.getProbe(); 4 5 private boolean lazyLoadingEnabled; 6 private boolean cacheModelsEnabled; 7 private boolean enhancementEnabled; 8 private boolean useColumnLabel = true; 9 private boolean forceMultipleResultSetSupport; 10 11 private TransactionManager txManager; 12 13 private HashMap mappedStatements; 14 private HashMap cacheModels; 15 private HashMap resultMaps; 16 private HashMap parameterMaps; 17 18 protected SqlExecutor sqlExecutor; 19 private TypeHandlerFactory typeHandlerFactory; 20 private DataExchangeFactory dataExchangeFactory; 21 22 private ResultObjectFactory resultObjectFactory; 23 private boolean statementCacheEnabled; 24 25 /** 26 * Default constructor 27 */ 28 public SqlMapExecutorDelegate() { 29 mappedStatements = new HashMap(); 30 cacheModels = new HashMap(); 31 resultMaps = new HashMap(); 32 parameterMaps = new HashMap(); 33 34 sqlExecutor = new SqlExecutor(); 35 typeHandlerFactory = new TypeHandlerFactory(); 36 dataExchangeFactory = new DataExchangeFactory(typeHandlerFactory); 37 } 38 39 public List queryForList(SessionScope sessionScope, String id, Object paramObject) throws SQLException { 40 return queryForList(sessionScope, id, paramObject, SqlExecutor.NO_SKIPPED_RESULTS, SqlExecutor.NO_MAXIMUM_RESULTS); 41 } 42 43 public List queryForList(SessionScope sessionScope, String id, Object paramObject, int skip, int max) throws SQLException { 44 List list = null; 45 46 MappedStatement ms = getMappedStatement(id); 47 Transaction trans = getTransaction(sessionScope); 48 boolean autoStart = trans == null; 49 50 try { 51 trans = autoStartTransaction(sessionScope, autoStart, trans); 52 53 StatementScope statementScope = beginStatementScope(sessionScope, ms); 54 try { 55 list = ms.executeQueryForList(statementScope, trans, paramObject, skip, max); 56 } finally { 57 endStatementScope(statementScope); 58 } 59 60 autoCommitTransaction(sessionScope, autoStart); 61 } finally { 62 autoEndTransaction(sessionScope, autoStart); 63 } 64 65 return list; 66 } 67 }
获取sessionScope、statementScope、MappedStatement、Transaction等相关实例,核心是调用MappedStatement的executeQueryForList方法:list = ms.executeQueryForList(statementScope, trans, paramObject, skip, max);
查看一下MappedStatement相关代码
1 public class MappedStatement { 2 private String id; 3 private Integer resultSetType; 4 private Integer fetchSize; 5 private ResultMap resultMap; 6 private ParameterMap parameterMap; 7 private Class parameterClass; 8 private Sql sql; 9 private int baseCacheKey; 10 private SqlMapClientImpl sqlMapClient; 11 private Integer timeout; 12 private ResultMap[] additionalResultMaps = new ResultMap[0]; 13 private List executeListeners = new ArrayList(); 14 private String resource; 15 16 public List executeQueryForList(StatementScope statementScope, Transaction trans, Object parameterObject, int skipResults, int maxResults) 17 throws SQLException { 18 try { 19 DefaultRowHandler rowHandler = new DefaultRowHandler(); 20 executeQueryWithCallback(statementScope, trans.getConnection(), parameterObject, null, rowHandler, skipResults, maxResults); 21 return rowHandler.getList(); 22 } catch (TransactionException e) { 23 throw new NestedSQLException("Error getting Connection from Transaction. Cause: " + e, e); 24 } 25 } 26 27 protected void executeQueryWithCallback(StatementScope statementScope, Connection conn, Object parameterObject, Object resultObject, RowHandler rowHandler, int skipResults, int maxResults) 28 throws SQLException { 29 ErrorContext errorContext = statementScope.getErrorContext(); 30 errorContext.setActivity("preparing the mapped statement for execution"); 31 errorContext.setObjectId(this.getId()); 32 errorContext.setResource(this.getResource()); 33 34 try { 35 parameterObject = validateParameter(parameterObject); 36 37 Sql sql = getSql(); 38 39 errorContext.setMoreInfo("Check the parameter map."); 40 ParameterMap parameterMap = sql.getParameterMap(statementScope, parameterObject); 41 42 errorContext.setMoreInfo("Check the result map."); 43 ResultMap resultMap = sql.getResultMap(statementScope, parameterObject); 44 45 statementScope.setResultMap(resultMap); 46 statementScope.setParameterMap(parameterMap); 47 48 errorContext.setMoreInfo("Check the parameter map."); 49 Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject); 50 51 errorContext.setMoreInfo("Check the SQL statement."); 52 String sqlString = sql.getSql(statementScope, parameterObject); 53 54 errorContext.setActivity("executing mapped statement"); 55 errorContext.setMoreInfo("Check the SQL statement or the result map."); 56 RowHandlerCallback callback = new RowHandlerCallback(resultMap, resultObject, rowHandler); 57 sqlExecuteQuery(statementScope, conn, sqlString, parameters, skipResults, maxResults, callback); 58 59 errorContext.setMoreInfo("Check the output parameters."); 60 if (parameterObject != null) { 61 postProcessParameterObject(statementScope, parameterObject, parameters); 62 } 63 64 errorContext.reset(); 65 sql.cleanup(statementScope); 66 notifyListeners(); 67 } catch (SQLException e) { 68 errorContext.setCause(e); 69 throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e); 70 } catch (Exception e) { 71 errorContext.setCause(e); 72 throw new NestedSQLException(errorContext.toString(), e); 73 } 74 } 75 }
protected void sqlExecuteQuery(StatementScope statementScope, Connection conn, String sqlString, Object[] parameters, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { getSqlExecutor().executeQuery(statementScope, conn, sqlString, parameters, skipResults, maxResults, callback); }
最终由SqlExecutor实现sql操作,实现代码
1 /** 2 * Long form of the method to execute a query 3 * 4 * @param statementScope - the request scope 5 * @param conn - the database connection 6 * @param sql - the SQL statement to execute 7 * @param parameters - the parameters for the statement 8 * @param skipResults - the number of results to skip 9 * @param maxResults - the maximum number of results to return 10 * @param callback - the row handler for the query 11 * @throws SQLException - if the query fails 12 */ 13 public void executeQuery(StatementScope statementScope, Connection conn, String sql, Object[] parameters, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { 14 ErrorContext errorContext = statementScope.getErrorContext(); 15 errorContext.setActivity("executing query"); 16 errorContext.setObjectId(sql); 17 PreparedStatement ps = null; 18 ResultSet rs = null; 19 setupResultObjectFactory(statementScope); 20 try { 21 errorContext.setMoreInfo("Check the SQL Statement (preparation failed)."); 22 Integer rsType = statementScope.getStatement().getResultSetType(); 23 if (rsType != null) { 24 ps = prepareStatement(statementScope.getSession(), conn, sql, rsType); 25 } else { 26 ps = prepareStatement(statementScope.getSession(), conn, sql); 27 } 28 setStatementTimeout(statementScope.getStatement(), ps); 29 Integer fetchSize = statementScope.getStatement().getFetchSize(); 30 if (fetchSize != null) { 31 ps.setFetchSize(fetchSize.intValue()); 32 } 33 errorContext.setMoreInfo("Check the parameters (set parameters failed)."); 34 statementScope.getParameterMap().setParameters(statementScope, ps, parameters); 35 errorContext.setMoreInfo("Check the statement (query failed)."); 36 ps.execute(); 37 errorContext.setMoreInfo("Check the results (failed to retrieve results)."); 38 39 // Begin ResultSet Handling 40 rs = handleMultipleResults(ps, statementScope, skipResults, maxResults, callback); 41 // End ResultSet Handling 42 } finally { 43 try { 44 closeResultSet(rs); 45 } finally { 46 closeStatement(statementScope.getSession(), ps); 47 } 48 } 49 50 }
handleMuiltipleResults方法代码
1 private ResultSet handleMultipleResults(PreparedStatement ps, StatementScope statementScope, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { 2 ResultSet rs; 3 rs = getFirstResultSet(statementScope, ps); 4 if (rs != null) { 5 handleResults(statementScope, rs, skipResults, maxResults, callback); 6 } 7 8 // Multiple ResultSet handling 9 if (callback.getRowHandler() instanceof DefaultRowHandler) { 10 MappedStatement statement = statementScope.getStatement(); 11 DefaultRowHandler defaultRowHandler = ((DefaultRowHandler) callback.getRowHandler()); 12 if (statement.hasMultipleResultMaps()) { 13 List multipleResults = new ArrayList(); 14 multipleResults.add(defaultRowHandler.getList()); 15 ResultMap[] resultMaps = statement.getAdditionalResultMaps(); 16 int i = 0; 17 while (moveToNextResultsSafely(statementScope, ps)) { 18 if (i >= resultMaps.length) break; 19 ResultMap rm = resultMaps[i]; 20 statementScope.setResultMap(rm); 21 rs = ps.getResultSet(); 22 DefaultRowHandler rh = new DefaultRowHandler(); 23 handleResults(statementScope, rs, skipResults, maxResults, new RowHandlerCallback(rm, null, rh)); 24 multipleResults.add(rh.getList()); 25 i++; 26 } 27 defaultRowHandler.setList(multipleResults); 28 statementScope.setResultMap(statement.getResultMap()); 29 } else { 30 while (moveToNextResultsSafely(statementScope, ps)) ; 31 } 32 } 33 // End additional ResultSet handling 34 return rs; 35 }