ibatis学习四---执行流程浅析
首先看一段最基本的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 }
 
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号