ibatis访问数据库的大致逻辑_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > ibatis访问数据库的大致逻辑

ibatis访问数据库的大致逻辑

 2013/12/11 19:09:06  wangzheng1989  程序员俱乐部  我要评论(0)
  • 摘要:创建SQL_Map_Config.xml文件<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEsqlMapConfigPUBLIC"-//ibatis.apache.org//DTDSQLMapConfig2.0//EN""http://ibatis.apache.org/dtd/sql-map-config-2.dtd"><sqlMapConfig><propertiesresource="jdbc
  • 标签:数据库 数据
  1. 创建SQL_Map_Config.xml文件
? ?
    monospace; margin-bottom: 1px; padding-top: 2px; padding-bottom: 2px; border: 1px solid #d1d7dc; color: #2b91af;">
  1. <?xml?version="1.0"?encoding="UTF-8"??>??
  2. <!DOCTYPE?sqlMapConfig????????
  3. ????PUBLIC?"-//ibatis.apache.org//DTD?SQL?Map?Config?2.0//EN"????????
  4. ????"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">??
  5. <sqlMapConfig>??
  6. ????<properties?resource="jdbc.properties"?/>??
  7. ????<transactionManager?type="JDBC">??
  8. ????????<dataSource?type="SIMPLE">??
  9. ????????????<property?name="JDBC.Driver"?value="${jdbc.driverClassName}"?/>??
  10. ????????????<property?name="JDBC.ConnectionURL"?value="${jdbc.url}"?/>??
  11. ????????????<property?name="JDBC.Username"?value="${jdbc.username}"?/>??
  12. ????????????<property?name="JDBC.Password"?value="${jdbc.password}"?/>??
  13. ????????</dataSource>??
  14. ????</transactionManager>??
  15. ????<sqlMap?resource="ibatis/resources/User.xml"?/>??
  16. </sqlMapConfig>??
? 这个文件设置了数据库连接的参数,以及存放SQL的SQLMap文件 ? 2.创建SQLMap文件 ?
  1. <?xml?version="1.0"?encoding="UTF-8"?>??
  2. <!DOCTYPE?sqlMap??????????
  3. ????PUBLIC?"-//ibatis.apache.org//DTD?SQL?Map?2.0//EN"??"http://ibatis.apache.org/dtd/sql-map-2.dtd"> ?
  4. <sqlMap>??
  5. ????<typeAlias?alias="User"?type="cn.yangphere.ibatisdemo.model.User"/>??
  6. ????<select?id="getAllUsers"?resultClass="User">??
  7. ????????select?id?as?userId,?userName?as?username,?password,?mobile,?email??
  8. ????????from?users??
  9. ????</select>??
  10. </sqlMap> ?
? ? 3.java调用
  1. package?ibatis;??
  2. import?ibatis.model.User;??
  3. import?java.io.*;??
  4. import?java.sql.SQLException;??
  5. import?java.util.List;??
  6. import?com.ibatis.common.resources.Resources;??
  7. import?com.ibatis.sqlmap.client.*;??
  8. public?class?IBatisDemo?{??
  9. ????public?static?void?main(String[]?args)?throws?IOException,?SQLException?{??
  10. ????????String?config?=?"ibatis/SqlMapConfig.xml";??
  11. ????????Reader?reader?=?Resources.getResourceAsReader(config);??
  12. ????????SqlMapClient?sqlMap?=?SqlMapClientBuilder.buildSqlMapClient(reader);??
  13. ????????List<User>?list?=?sqlMap.queryForList("getAllUsers");??
  14. ????????for?(User?user?:?list)?{??
  15. ????????????System.out.println(user);??
  16. ????????}??
  17. ????}??
  18. } ?
这样一个基本的ibatis使用例子就完成了 ? ? 这个调用代码里,有两个方面的操作,
  1. 根据sqlmapconfig.xml文件生成client对象
  2. 用client对象访问CRUD方法,来访问数据库
? ? 先来看看根据sqlmapconfig.xml文件生成client对象: 1.SqlMapClient?sqlMap?=?SqlMapClientBuilder.buildSqlMapClient(reader);? ?看看buildSqlMapClient方法的代码:
  /**
   * 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.接着往下看
Open Declaration?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类继承了BaseStatement BaseStatement又实现了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
? ? ? ? ? ? ? ? ?
发表评论
用户名: 匿名