zoukankan      html  css  js  c++  java
  • 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   }
  • 相关阅读:
    mybatis框架demo first
    pro02总结:spring mvc + jdbc
    java开发常用jar包介绍(转载)
    proj01总结:spring jdbc操作
    mysql导入sql文件
    hibernate对象三种状态
    Hibernate 的saveOrUpdate方法(转)
    java web面试题,收集
    redis与spring整合·
    mybatis_2
  • 原文地址:https://www.cnblogs.com/waimai/p/2847460.html
Copyright © 2011-2022 走看看