iBatis分页

1 篇文章 0 订阅

转自:http://wt8414.iteye.com/blog/544765

 

最近在学习iBatis的分页功能,iBatis默认的分页是采用游标滚动的方式来实现的,这种方式在大数据量的情况下便会OOM了,因此一般都采用手写分页SQL语句使用数据库物理分页方式实现,参考了网上很多网友所写的如何实现像hibernate一样使用方言的方式来实现分页功能,基本上千篇一律都是继承com.ibatis.sqlmap.engine.execution.SqlExecutor类然后在spring中进行注入等等,操作复杂编码甚多,方法不可取。
    另外还有些是修改iBatis的jar包来实现,本人觉得这种方法更不可取。
    基于网友们的思想,自己实现了另一种方法,不用修改源码,不用在spring中做任何配置即可实现物理分页功能:
条件
    1、JVM类的加载是通过Class.forName(String cls)来实现,根据这个原理可以自己写一个与com.ibatis.sqlmap.engine.execution.SqlExecutor同名类;
    2、java web类的加载顺序是:首先是web容器的相关类与jar包,然后是web工程下面WEB-INF/classes/下的所有类,最后才是WEB-INF/lib下的所有jar包;
    有了以上的先决条件就好办了,可以在你的项目src目录下建包com.ibatis.sqlmap.engine.execution,然后在此包下建类SqlExecutor,然后把iBatis包下的这个类的源码复制进来后做小小改动,原来的executeQuery方法改成私有、换名,换成什么名称随便,然后新建一个公有的executeQuery方法,分页功能就在这个方法体内实现;
这样一来,web容器首会找到WEB-INF/classes下的com.ibatis.sqlmap.engine.execution.SqlExecutor这个类,因而会忽略掉在ibatis包中的这个类,即实现了自定义的分页功能,又不用去破坏ibatis的包;
    还有一点,也可以将自定义的这个类打成jar包放到lib中去,不过这时就要注意了,jar包的名称一定要在ibatis包的名称之前,也就是说ibatis-2.3.4.726.jar,那么这个jar就可以写成ibatis-2.3.4.725.jar,或者字母在ibatis这几个字母之前,这样才能正确加载自己写的那个类。
贴上代码:
SqlExecutor.java

Java代码 复制代码 收藏代码
  1. /*
  2. *  Copyright 2004 Clinton Begin
  3. *
  4. *  Licensed under the Apache License, Version 2.0 (the "License");
  5. *  you may not use this file except in compliance with the License.
  6. *  You may obtain a copy of the License at
  7. *
  8. *      http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *  Unless required by applicable law or agreed to in writing, software
  11. *  distributed under the License is distributed on an "AS IS" BASIS,
  12. *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. *  See the License for the specific language governing permissions and
  14. *  limitations under the License.
  15. */ 
  16. package com.ibatis.sqlmap.engine.execution; 
  17.  
  18. import java.sql.BatchUpdateException; 
  19. import java.sql.CallableStatement; 
  20. import java.sql.Connection; 
  21. import java.sql.PreparedStatement; 
  22. import java.sql.ResultSet; 
  23. import java.sql.SQLException; 
  24. import java.sql.Statement; 
  25. import java.sql.Types; 
  26. import java.util.ArrayList; 
  27. import java.util.List; 
  28.  
  29. import org.apache.commons.logging.Log; 
  30. import org.apache.commons.logging.LogFactory; 
  31.  
  32. import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl; 
  33. import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate; 
  34. import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap; 
  35. import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping; 
  36. import com.ibatis.sqlmap.engine.mapping.result.ResultMap; 
  37. import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactoryUtil; 
  38. import com.ibatis.sqlmap.engine.mapping.statement.DefaultRowHandler; 
  39. import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement; 
  40. import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback; 
  41. import com.ibatis.sqlmap.engine.scope.ErrorContext; 
  42. import com.ibatis.sqlmap.engine.scope.SessionScope; 
  43. import com.ibatis.sqlmap.engine.scope.StatementScope; 
  44.  
  45. /**
  46. * Class responsible for executing the SQL
  47. */ 
  48. @SuppressWarnings ("unchecked"
  49. public class SqlExecutor { 
  50.  
  51.     private static final Log log = LogFactory.getLog(SqlExecutor.class); 
  52.     // 
  53.     // Constants 
  54.     // 
  55.     /**
  56.      * Constant to let us know not to skip anything
  57.      */ 
  58.     public static final int NO_SKIPPED_RESULTS = 0
  59.     /**
  60.      * Constant to let us know to include all records
  61.      */ 
  62.     public static final int NO_MAXIMUM_RESULTS = -999999
  63.      
  64.     public SqlExecutor() { 
  65.         log.info("Custom class 'SqlExecutor' Initialization"); 
  66.     } 
  67.  
  68.     // 
  69.     // Public Methods 
  70.     // 
  71.  
  72.     /**
  73.      * Execute an update
  74.      *
  75.      * @param statementScope
  76.      *            - the request scope
  77.      * @param conn
  78.      *            - the database connection
  79.      * @param sql
  80.      *            - the sql statement to execute
  81.      * @param parameters
  82.      *            - the parameters for the sql statement
  83.      * @return - the number of records changed
  84.      * @throws SQLException
  85.      *             - if the update fails
  86.      */ 
  87.     public int executeUpdate(StatementScope statementScope, Connection conn, 
  88.             String sql, Object[] parameters) throws SQLException { 
  89.         ErrorContext errorContext = statementScope.getErrorContext(); 
  90.         errorContext.setActivity("executing update"); 
  91.         errorContext.setObjectId(sql); 
  92.         PreparedStatement ps = null
  93.         setupResultObjectFactory(statementScope); 
  94.         int rows = 0
  95.         try
  96.             errorContext 
  97.                     .setMoreInfo("Check the SQL Statement (preparation failed)."); 
  98.             ps = prepareStatement(statementScope.getSession(), conn, sql); 
  99.             setStatementTimeout(statementScope.getStatement(), ps); 
  100.             errorContext 
  101.                     .setMoreInfo("Check the parameters (set parameters failed)."); 
  102.             statementScope.getParameterMap().setParameters(statementScope, ps, 
  103.                     parameters); 
  104.             errorContext.setMoreInfo("Check the statement (update failed)."); 
  105.             ps.execute(); 
  106.             rows = ps.getUpdateCount(); 
  107.         } finally
  108.             closeStatement(statementScope.getSession(), ps); 
  109.         } 
  110.         return rows; 
  111.     } 
  112.  
  113.     /**
  114.      * Adds a statement to a batch
  115.      *
  116.      * @param statementScope
  117.      *            - the request scope
  118.      * @param conn
  119.      *            - the database connection
  120.      * @param sql
  121.      *            - the sql statement
  122.      * @param parameters
  123.      *            - the parameters for the statement
  124.      * @throws SQLException
  125.      *             - if the statement fails
  126.      */ 
  127.     public void addBatch(StatementScope statementScope, Connection conn, 
  128.             String sql, Object[] parameters) throws SQLException { 
  129.         Batch batch = (Batch) statementScope.getSession().getBatch(); 
  130.         if (batch == null) { 
  131.             batch = new Batch(); 
  132.             statementScope.getSession().setBatch(batch); 
  133.         } 
  134.         batch.addBatch(statementScope, conn, sql, parameters); 
  135.     } 
  136.  
  137.     /**
  138.      * Execute a batch of statements
  139.      *
  140.      * @param sessionScope
  141.      *            - the session scope
  142.      * @return - the number of rows impacted by the batch
  143.      * @throws SQLException
  144.      *             - if a statement fails
  145.      */ 
  146.     public int executeBatch(SessionScope sessionScope) throws SQLException { 
  147.         int rows = 0
  148.         Batch batch = (Batch) sessionScope.getBatch(); 
  149.         if (batch != null) { 
  150.             try
  151.                 rows = batch.executeBatch(); 
  152.             } finally
  153.                 batch.cleanupBatch(sessionScope); 
  154.             } 
  155.         } 
  156.         return rows; 
  157.     } 
  158.  
  159.     /**
  160.      * Execute a batch of statements
  161.      *
  162.      * @param sessionScope
  163.      *            - the session scope
  164.      * @return - a List of BatchResult objects (may be null if no batch has been
  165.      *         initiated). There will be one BatchResult object in the list for
  166.      *         each sub-batch executed
  167.      * @throws SQLException
  168.      *             if a database access error occurs, or the drive does not
  169.      *             support batch statements
  170.      * @throws BatchException
  171.      *             if the driver throws BatchUpdateException
  172.      */ 
  173.     public List executeBatchDetailed(SessionScope sessionScope) 
  174.             throws SQLException, BatchException { 
  175.         List answer = null
  176.         Batch batch = (Batch) sessionScope.getBatch(); 
  177.         if (batch != null) { 
  178.             try
  179.                 answer = batch.executeBatchDetailed(); 
  180.             } finally
  181.                 batch.cleanupBatch(sessionScope); 
  182.             } 
  183.         } 
  184.         return answer; 
  185.     } 
  186.  
  187.     /**
  188.      * Long form of the method to execute a query
  189.      *
  190.      * @param statementScope
  191.      *            - the request scope
  192.      * @param conn
  193.      *            - the database connection
  194.      * @param sql
  195.      *            - the SQL statement to execute
  196.      * @param parameters
  197.      *            - the parameters for the statement
  198.      * @param skipResults
  199.      *            - the number of results to skip
  200.      * @param maxResults
  201.      *            - the maximum number of results to return
  202.      * @param callback
  203.      *            - the row handler for the query
  204.      * @throws SQLException
  205.      *             - if the query fails
  206.      */ 
  207. //------------------------------- 分页代码重写(start) ------------------------------------// 
  208.     //重写executeQuery方法,首先判断是否分页查询,分页查询先将分页SQL语句构建,然后执行iBatis默认的查询 
  209.     public void executeQuery(StatementScope statementScope, Connection conn, 
  210.             String sql, Object[] parameters, int skipResults, int maxResults, 
  211.             RowHandlerCallback callback) throws SQLException { 
  212.         //取数据库产品名称 
  213.         String dbName = conn.getMetaData().getDatabaseProductName(); 
  214.          
  215.         int len = sql.length(); 
  216.          
  217.         //判断是否分页 
  218.         if ((skipResults != NO_SKIPPED_RESULTS || maxResults != NO_MAXIMUM_RESULTS)) { 
  219.             //根据数据库产品名称取对应的分页SQL语句 
  220.             sql = Dialect.getLimitString(dbName, sql, skipResults, maxResults); 
  221.              
  222.             //分页语句是否存在 
  223.             if (sql.length() != len) { 
  224.                 skipResults = NO_SKIPPED_RESULTS; 
  225.                 maxResults = NO_MAXIMUM_RESULTS; 
  226.             } 
  227.         } 
  228.         iBatisExecuteQuery(statementScope, conn, sql, parameters, skipResults, 
  229.                 maxResults, callback); 
  230.     } 
  231.      
  232.     //iBatis包中默认的executeQuery方法 
  233.     private void iBatisExecuteQuery(StatementScope statementScope, 
  234.             Connection conn, String sql, Object[] parameters, int skipResults, 
  235.             int maxResults, RowHandlerCallback callback) throws SQLException { 
  236.         ErrorContext errorContext = statementScope.getErrorContext(); 
  237.         errorContext.setActivity("executing query"); 
  238.         errorContext.setObjectId(sql); 
  239.         PreparedStatement ps = null
  240.         ResultSet rs = null
  241.         setupResultObjectFactory(statementScope); 
  242.         try
  243.             errorContext 
  244.                     .setMoreInfo("Check the SQL Statement (preparation failed)."); 
  245.             Integer rsType = statementScope.getStatement().getResultSetType(); 
  246.             if (rsType != null) { 
  247.                 ps = prepareStatement(statementScope.getSession(), conn, sql, 
  248.                         rsType); 
  249.             } else
  250.                 ps = prepareStatement(statementScope.getSession(), conn, sql); 
  251.             } 
  252.             setStatementTimeout(statementScope.getStatement(), ps); 
  253.             Integer fetchSize = statementScope.getStatement().getFetchSize(); 
  254.             if (fetchSize != null) { 
  255.                 ps.setFetchSize(fetchSize.intValue()); 
  256.             } 
  257.             errorContext 
  258.                     .setMoreInfo("Check the parameters (set parameters failed)."); 
  259.             statementScope.getParameterMap().setParameters(statementScope, ps, 
  260.                     parameters); 
  261.             errorContext.setMoreInfo("Check the statement (query failed)."); 
  262.             ps.execute(); 
  263.             errorContext 
  264.                     .setMoreInfo("Check the results (failed to retrieve results)."); 
  265.  
  266.             // Begin ResultSet Handling 
  267.             rs = handleMultipleResults(ps, statementScope, skipResults, 
  268.                     maxResults, callback); 
  269.             // End ResultSet Handling 
  270.         } finally
  271.             try
  272.                 closeResultSet(rs); 
  273.             } finally
  274.                 closeStatement(statementScope.getSession(), ps); 
  275.             } 
  276.         } 
  277.     } 
  278. //-------------------- 分页代码重写(end) -------------------------------------// 
  279.     /**
  280.      * Execute a stored procedure that updates data
  281.      *
  282.      * @param statementScope
  283.      *            - the request scope
  284.      * @param conn
  285.      *            - the database connection
  286.      * @param sql
  287.      *            - the SQL to call the procedure
  288.      * @param parameters
  289.      *            - the parameters for the procedure
  290.      * @return - the rows impacted by the procedure
  291.      * @throws SQLException
  292.      *             - if the procedure fails
  293.      */ 
  294.     public int executeUpdateProcedure(StatementScope statementScope, 
  295.             Connection conn, String sql, Object[] parameters) 
  296.             throws SQLException { 
  297.         ErrorContext errorContext = statementScope.getErrorContext(); 
  298.         errorContext.setActivity("executing update procedure"); 
  299.         errorContext.setObjectId(sql); 
  300.         CallableStatement cs = null
  301.         setupResultObjectFactory(statementScope); 
  302.         int rows = 0
  303.         try
  304.             errorContext 
  305.                     .setMoreInfo("Check the SQL Statement (preparation failed)."); 
  306.             cs = prepareCall(statementScope.getSession(), conn, sql); 
  307.             setStatementTimeout(statementScope.getStatement(), cs); 
  308.             ParameterMap parameterMap = statementScope.getParameterMap(); 
  309.             ParameterMapping[] mappings = parameterMap.getParameterMappings(); 
  310.             errorContext 
  311.                     .setMoreInfo("Check the output parameters (register output parameters failed)."); 
  312.             registerOutputParameters(cs, mappings); 
  313.             errorContext 
  314.                     .setMoreInfo("Check the parameters (set parameters failed)."); 
  315.             parameterMap.setParameters(statementScope, cs, parameters); 
  316.             errorContext 
  317.                     .setMoreInfo("Check the statement (update procedure failed)."); 
  318.             cs.execute(); 
  319.             rows = cs.getUpdateCount(); 
  320.             errorContext 
  321.                     .setMoreInfo("Check the output parameters (retrieval of output parameters failed)."); 
  322.             retrieveOutputParameters(statementScope, cs, mappings, parameters, 
  323.                     null); 
  324.         } finally
  325.             closeStatement(statementScope.getSession(), cs); 
  326.         } 
  327.         return rows; 
  328.     } 
  329.  
  330.     /**
  331.      * Execute a stored procedure
  332.      *
  333.      * @param statementScope
  334.      *            - the request scope
  335.      * @param conn
  336.      *            - the database connection
  337.      * @param sql
  338.      *            - the sql to call the procedure
  339.      * @param parameters
  340.      *            - the parameters for the procedure
  341.      * @param skipResults
  342.      *            - the number of results to skip
  343.      * @param maxResults
  344.      *            - the maximum number of results to return
  345.      * @param callback
  346.      *            - a row handler for processing the results
  347.      * @throws SQLException
  348.      *             - if the procedure fails
  349.      */ 
  350.     public void executeQueryProcedure(StatementScope statementScope, 
  351.             Connection conn, String sql, Object[] parameters, int skipResults, 
  352.             int maxResults, RowHandlerCallback callback) throws SQLException { 
  353.         ErrorContext errorContext = statementScope.getErrorContext(); 
  354.         errorContext.setActivity("executing query procedure"); 
  355.         errorContext.setObjectId(sql); 
  356.         CallableStatement cs = null
  357.         ResultSet rs = null
  358.         setupResultObjectFactory(statementScope); 
  359.         try
  360.             errorContext 
  361.                     .setMoreInfo("Check the SQL Statement (preparation failed)."); 
  362.             Integer rsType = statementScope.getStatement().getResultSetType(); 
  363.             if (rsType != null) { 
  364.                 cs = prepareCall(statementScope.getSession(), conn, sql, rsType); 
  365.             } else
  366.                 cs = prepareCall(statementScope.getSession(), conn, sql); 
  367.             } 
  368.             setStatementTimeout(statementScope.getStatement(), cs); 
  369.             Integer fetchSize = statementScope.getStatement().getFetchSize(); 
  370.             if (fetchSize != null) { 
  371.                 cs.setFetchSize(fetchSize.intValue()); 
  372.             } 
  373.             ParameterMap parameterMap = statementScope.getParameterMap(); 
  374.             ParameterMapping[] mappings = parameterMap.getParameterMappings(); 
  375.             errorContext 
  376.                     .setMoreInfo("Check the output parameters (register output parameters failed)."); 
  377.             registerOutputParameters(cs, mappings); 
  378.             errorContext 
  379.                     .setMoreInfo("Check the parameters (set parameters failed)."); 
  380.             parameterMap.setParameters(statementScope, cs, parameters); 
  381.             errorContext 
  382.                     .setMoreInfo("Check the statement (update procedure failed)."); 
  383.             cs.execute(); 
  384.             errorContext 
  385.                     .setMoreInfo("Check the results (failed to retrieve results)."); 
  386.  
  387.             // Begin ResultSet Handling 
  388.             rs = handleMultipleResults(cs, statementScope, skipResults, 
  389.                     maxResults, callback); 
  390.             // End ResultSet Handling 
  391.             errorContext 
  392.                     .setMoreInfo("Check the output parameters (retrieval of output parameters failed)."); 
  393.             retrieveOutputParameters(statementScope, cs, mappings, parameters, 
  394.                     callback); 
  395.  
  396.         } finally
  397.             try
  398.                 closeResultSet(rs); 
  399.             } finally
  400.                 closeStatement(statementScope.getSession(), cs); 
  401.             } 
  402.         } 
  403.     } 
  404.  
  405.     private ResultSet handleMultipleResults(PreparedStatement ps, 
  406.             StatementScope statementScope, int skipResults, int maxResults, 
  407.             RowHandlerCallback callback) throws SQLException { 
  408.         ResultSet rs; 
  409.         rs = getFirstResultSet(statementScope, ps); 
  410.         if (rs != null) { 
  411.             handleResults(statementScope, rs, skipResults, maxResults, callback); 
  412.         } 
  413.  
  414.         // Multiple ResultSet handling 
  415.         if (callback.getRowHandler() instanceof DefaultRowHandler) { 
  416.             MappedStatement statement = statementScope.getStatement(); 
  417.             DefaultRowHandler defaultRowHandler = ((DefaultRowHandler) callback 
  418.                     .getRowHandler()); 
  419.             if (statement.hasMultipleResultMaps()) { 
  420.                 List multipleResults = new ArrayList(); 
  421.                 multipleResults.add(defaultRowHandler.getList()); 
  422.                 ResultMap[] resultMaps = statement.getAdditionalResultMaps(); 
  423.                 int i = 0
  424.                 while (moveToNextResultsSafely(statementScope, ps)) { 
  425.                     if (i >= resultMaps.length) 
  426.                         break
  427.                     ResultMap rm = resultMaps[i]; 
  428.                     statementScope.setResultMap(rm); 
  429.                     rs = ps.getResultSet(); 
  430.                     DefaultRowHandler rh = new DefaultRowHandler(); 
  431.                     handleResults(statementScope, rs, skipResults, maxResults, 
  432.                             new RowHandlerCallback(rm, null, rh)); 
  433.                     multipleResults.add(rh.getList()); 
  434.                     i++; 
  435.                 } 
  436.                 defaultRowHandler.setList(multipleResults); 
  437.                 statementScope.setResultMap(statement.getResultMap()); 
  438.             } else
  439.                 while (moveToNextResultsSafely(statementScope, ps)) 
  440.                     ; 
  441.             } 
  442.         } 
  443.         // End additional ResultSet handling 
  444.         return rs; 
  445.     } 
  446.  
  447.     private ResultSet getFirstResultSet(StatementScope scope, Statement stmt) 
  448.             throws SQLException { 
  449.         ResultSet rs = null
  450.         boolean hasMoreResults = true
  451.         while (hasMoreResults) { 
  452.             rs = stmt.getResultSet(); 
  453.             if (rs != null) { 
  454.                 break
  455.             } 
  456.             hasMoreResults = moveToNextResultsIfPresent(scope, stmt); 
  457.         } 
  458.         return rs; 
  459.     } 
  460.  
  461.     private boolean moveToNextResultsIfPresent(StatementScope scope, 
  462.             Statement stmt) throws SQLException { 
  463.         boolean moreResults; 
  464.         // This is the messed up JDBC approach for determining if there are more 
  465.         // results 
  466.         moreResults = !(((moveToNextResultsSafely(scope, stmt) == false) && (stmt 
  467.                 .getUpdateCount() == -1))); 
  468.         return moreResults; 
  469.     } 
  470.  
  471.     private boolean moveToNextResultsSafely(StatementScope scope, Statement stmt) 
  472.             throws SQLException { 
  473.         if (forceMultipleResultSetSupport(scope) 
  474.                 || stmt.getConnection().getMetaData() 
  475.                         .supportsMultipleResultSets()) { 
  476.             return stmt.getMoreResults(); 
  477.         } 
  478.         return false
  479.     } 
  480.  
  481.     private boolean forceMultipleResultSetSupport(StatementScope scope) { 
  482.         return ((SqlMapClientImpl) scope.getSession().getSqlMapClient()) 
  483.                 .getDelegate().isForceMultipleResultSetSupport(); 
  484.     } 
  485.  
  486.     private void handleResults(StatementScope statementScope, ResultSet rs, 
  487.             int skipResults, int maxResults, RowHandlerCallback callback) 
  488.             throws SQLException { 
  489.         try
  490.             statementScope.setResultSet(rs); 
  491.             ResultMap resultMap = statementScope.getResultMap(); 
  492.             if (resultMap != null) { 
  493.                 // Skip Results 
  494.                 if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) { 
  495.                     if (skipResults > 0) { 
  496.                         rs.absolute(skipResults); 
  497.                     } 
  498.                 } else
  499.                     for (int i = 0; i < skipResults; i++) { 
  500.                         if (!rs.next()) { 
  501.                             return
  502.                         } 
  503.                     } 
  504.                 } 
  505.  
  506.                 // Get Results 
  507.                 int resultsFetched = 0
  508.                 while ((maxResults == SqlExecutor.NO_MAXIMUM_RESULTS || resultsFetched < maxResults) 
  509.                         && rs.next()) { 
  510.                     Object[] columnValues = resultMap.resolveSubMap( 
  511.                             statementScope, rs).getResults(statementScope, rs); 
  512.                     callback.handleResultObject(statementScope, columnValues, 
  513.                             rs); 
  514.                     resultsFetched++; 
  515.                 } 
  516.             } 
  517.         } finally
  518.             statementScope.setResultSet(null); 
  519.         } 
  520.     } 
  521.  
  522.     private void retrieveOutputParameters(StatementScope statementScope, 
  523.             CallableStatement cs, ParameterMapping[] mappings, 
  524.             Object[] parameters, RowHandlerCallback callback) 
  525.             throws SQLException { 
  526.         for (int i = 0; i < mappings.length; i++) { 
  527.             ParameterMapping mapping = ((ParameterMapping) mappings[i]); 
  528.             if (mapping.isOutputAllowed()) { 
  529.                 if ("java.sql.ResultSet".equalsIgnoreCase(mapping 
  530.                         .getJavaTypeName())) { 
  531.                     ResultSet rs = (ResultSet) cs.getObject(i + 1); 
  532.                     ResultMap resultMap; 
  533.                     if (mapping.getResultMapName() == null) { 
  534.                         resultMap = statementScope.getResultMap(); 
  535.                         handleOutputParameterResults(statementScope, resultMap, 
  536.                                 rs, callback); 
  537.                     } else
  538.                         SqlMapClientImpl client = (SqlMapClientImpl) statementScope 
  539.                                 .getSession().getSqlMapClient(); 
  540.                         resultMap = client.getDelegate().getResultMap( 
  541.                                 mapping.getResultMapName()); 
  542.                         DefaultRowHandler rowHandler = new DefaultRowHandler(); 
  543.                         RowHandlerCallback handlerCallback = new RowHandlerCallback( 
  544.                                 resultMap, null, rowHandler); 
  545.                         handleOutputParameterResults(statementScope, resultMap, 
  546.                                 rs, handlerCallback); 
  547.                         parameters[i] = rowHandler.getList(); 
  548.                     } 
  549.                     rs.close(); 
  550.                 } else
  551.                     parameters[i] = mapping.getTypeHandler().getResult(cs, 
  552.                             i + 1); 
  553.                 } 
  554.             } 
  555.         } 
  556.     } 
  557.  
  558.     private void registerOutputParameters(CallableStatement cs, 
  559.             ParameterMapping[] mappings) throws SQLException { 
  560.         for (int i = 0; i < mappings.length; i++) { 
  561.             ParameterMapping mapping = ((ParameterMapping) mappings[i]); 
  562.             if (mapping.isOutputAllowed()) { 
  563.                 if (null != mapping.getTypeName() 
  564.                         && !mapping.getTypeName().equals("")) { // @added 
  565.                     cs.registerOutParameter(i + 1, mapping.getJdbcType(), 
  566.                             mapping.getTypeName()); 
  567.                 } else
  568.                     if (mapping.getNumericScale() != null 
  569.                             && (mapping.getJdbcType() == Types.NUMERIC || mapping 
  570.                                     .getJdbcType() == Types.DECIMAL)) { 
  571.                         cs.registerOutParameter(i + 1, mapping.getJdbcType(), 
  572.                                 mapping.getNumericScale().intValue()); 
  573.                     } else
  574.                         cs.registerOutParameter(i + 1, mapping.getJdbcType()); 
  575.                     } 
  576.                 } 
  577.             } 
  578.         } 
  579.     } 
  580.  
  581.     private void handleOutputParameterResults(StatementScope statementScope, 
  582.             ResultMap resultMap, ResultSet rs, RowHandlerCallback callback) 
  583.             throws SQLException { 
  584.         ResultMap orig = statementScope.getResultMap(); 
  585.         try
  586.             statementScope.setResultSet(rs); 
  587.             if (resultMap != null) { 
  588.                 statementScope.setResultMap(resultMap); 
  589.  
  590.                 // Get Results 
  591.                 while (rs.next()) { 
  592.                     Object[] columnValues = resultMap.resolveSubMap( 
  593.                             statementScope, rs).getResults(statementScope, rs); 
  594.                     callback.handleResultObject(statementScope, columnValues, 
  595.                             rs); 
  596.                 } 
  597.             } 
  598.         } finally
  599.             statementScope.setResultSet(null); 
  600.             statementScope.setResultMap(orig); 
  601.         } 
  602.     } 
  603.  
  604.     /**
  605.      * Clean up any batches on the session
  606.      *
  607.      * @param sessionScope
  608.      *            - the session to clean up
  609.      */ 
  610.     public void cleanup(SessionScope sessionScope) { 
  611.         Batch batch = (Batch) sessionScope.getBatch(); 
  612.         if (batch != null) { 
  613.             batch.cleanupBatch(sessionScope); 
  614.             sessionScope.setBatch(null); 
  615.         } 
  616.     } 
  617.  
  618.     private PreparedStatement prepareStatement(SessionScope sessionScope, 
  619.             Connection conn, String sql, Integer rsType) throws SQLException { 
  620.         SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope 
  621.                 .getSqlMapExecutor()).getDelegate(); 
  622.         if (sessionScope.hasPreparedStatementFor(sql)) { 
  623.             return sessionScope.getPreparedStatement((sql)); 
  624.         } else
  625.             PreparedStatement ps = conn.prepareStatement(sql, 
  626.                     rsType.intValue(), ResultSet.CONCUR_READ_ONLY); 
  627.             sessionScope.putPreparedStatement(delegate, sql, ps); 
  628.             return ps; 
  629.         } 
  630.     } 
  631.  
  632.     private CallableStatement prepareCall(SessionScope sessionScope, 
  633.             Connection conn, String sql, Integer rsType) throws SQLException { 
  634.         SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope 
  635.                 .getSqlMapExecutor()).getDelegate(); 
  636.         if (sessionScope.hasPreparedStatementFor(sql)) { 
  637.             return (CallableStatement) sessionScope.getPreparedStatement((sql)); 
  638.         } else
  639.             CallableStatement cs = conn.prepareCall(sql, rsType.intValue(), 
  640.                     ResultSet.CONCUR_READ_ONLY); 
  641.             sessionScope.putPreparedStatement(delegate, sql, cs); 
  642.             return cs; 
  643.         } 
  644.     } 
  645.  
  646.     private static PreparedStatement prepareStatement( 
  647.             SessionScope sessionScope, Connection conn, String sql) 
  648.             throws SQLException { 
  649.         SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope 
  650.                 .getSqlMapExecutor()).getDelegate(); 
  651.         if (sessionScope.hasPreparedStatementFor(sql)) { 
  652.             return sessionScope.getPreparedStatement((sql)); 
  653.         } else
  654.             PreparedStatement ps = conn.prepareStatement(sql); 
  655.             sessionScope.putPreparedStatement(delegate, sql, ps); 
  656.             return ps; 
  657.         } 
  658.     } 
  659.  
  660.     private CallableStatement prepareCall(SessionScope sessionScope, 
  661.             Connection conn, String sql) throws SQLException { 
  662.         SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope 
  663.                 .getSqlMapExecutor()).getDelegate(); 
  664.         if (sessionScope.hasPreparedStatementFor(sql)) { 
  665.             return (CallableStatement) sessionScope.getPreparedStatement((sql)); 
  666.         } else
  667.             CallableStatement cs = conn.prepareCall(sql); 
  668.             sessionScope.putPreparedStatement(delegate, sql, cs); 
  669.             return cs; 
  670.         } 
  671.     } 
  672.  
  673.     private static void closeStatement(SessionScope sessionScope, 
  674.             PreparedStatement ps) { 
  675.         if (ps != null) { 
  676.             if (!sessionScope.hasPreparedStatement(ps)) { 
  677.                 try
  678.                     ps.close(); 
  679.                 } catch (SQLException e) { 
  680.                     // ignore 
  681.                 } 
  682.             } 
  683.         } 
  684.     } 
  685.  
  686.     /**
  687.      * @param rs
  688.      */ 
  689.     private static void closeResultSet(ResultSet rs) { 
  690.         if (rs != null) { 
  691.             try
  692.                 rs.close(); 
  693.             } catch (SQLException e) { 
  694.                 // ignore 
  695.             } 
  696.         } 
  697.     } 
  698.  
  699.     private static void setStatementTimeout(MappedStatement mappedStatement, 
  700.             Statement statement) throws SQLException { 
  701.         if (mappedStatement.getTimeout() != null) { 
  702.             statement.setQueryTimeout(mappedStatement.getTimeout().intValue()); 
  703.         } 
  704.     } 
  705.  
  706.     // 
  707.     // Inner Classes 
  708.     // 
  709.  
  710.     private static class Batch { 
  711.         private String currentSql; 
  712.         private List statementList = new ArrayList(); 
  713.         private List batchResultList = new ArrayList(); 
  714.         private int size; 
  715.  
  716.         /**
  717.          * Create a new batch
  718.          */ 
  719.         public Batch() { 
  720.             this.size = 0
  721.         } 
  722.  
  723.         /**
  724.          * Getter for the batch size
  725.          *
  726.          * @return - the batch size
  727.          */ 
  728.         public int getSize() { 
  729.             return size; 
  730.         } 
  731.  
  732.         /**
  733.          * Add a prepared statement to the batch
  734.          *
  735.          * @param statementScope
  736.          *            - the request scope
  737.          * @param conn
  738.          *            - the database connection
  739.          * @param sql
  740.          *            - the SQL to add
  741.          * @param parameters
  742.          *            - the parameters for the SQL
  743.          * @throws SQLException
  744.          *             - if the prepare for the SQL fails
  745.          */ 
  746.         public void addBatch(StatementScope statementScope, Connection conn, 
  747.                 String sql, Object[] parameters) throws SQLException { 
  748.             PreparedStatement ps = null
  749.             if (currentSql != null && currentSql.equals(sql)) { 
  750.                 int last = statementList.size() - 1
  751.                 ps = (PreparedStatement) statementList.get(last); 
  752.             } else
  753.                 ps = prepareStatement(statementScope.getSession(), conn, sql); 
  754.                 setStatementTimeout(statementScope.getStatement(), ps); 
  755.                 currentSql = sql; 
  756.                 statementList.add(ps); 
  757.                 batchResultList.add(new BatchResult(statementScope 
  758.                         .getStatement().getId(), sql)); 
  759.             } 
  760.             statementScope.getParameterMap().setParameters(statementScope, ps, 
  761.                     parameters); 
  762.             ps.addBatch(); 
  763.             size++; 
  764.         } 
  765.  
  766.         /**
  767.          * TODO (Jeff Butler) - maybe this method should be deprecated in some
  768.          * release, and then removed in some even later release.
  769.          * executeBatchDetailed gives much more complete information. <p/>
  770.          * Execute the current session's batch
  771.          *
  772.          * @return - the number of rows updated
  773.          * @throws SQLException
  774.          *             - if the batch fails
  775.          */ 
  776.         public int executeBatch() throws SQLException { 
  777.             int totalRowCount = 0
  778.             for (int i = 0, n = statementList.size(); i < n; i++) { 
  779.                 PreparedStatement ps = (PreparedStatement) statementList.get(i); 
  780.                 int[] rowCounts = ps.executeBatch(); 
  781.                 for (int j = 0; j < rowCounts.length; j++) { 
  782.                     if (rowCounts[j] == Statement.SUCCESS_NO_INFO) { 
  783.                         // do nothing 
  784.                     } else if (rowCounts[j] == Statement.EXECUTE_FAILED) { 
  785.                         throw new SQLException( 
  786.                                 "The batched statement at index " + j 
  787.                                         + " failed to execute."); 
  788.                     } else
  789.                         totalRowCount += rowCounts[j]; 
  790.                     } 
  791.                 } 
  792.             } 
  793.             return totalRowCount; 
  794.         } 
  795.  
  796.         /**
  797.          * Batch execution method that returns all the information the driver
  798.          * has to offer.
  799.          *
  800.          * @return a List of BatchResult objects
  801.          * @throws BatchException
  802.          *             (an SQLException sub class) if any nested batch fails
  803.          * @throws SQLException
  804.          *             if a database access error occurs, or the drive does not
  805.          *             support batch statements
  806.          * @throws BatchException
  807.          *             if the driver throws BatchUpdateException
  808.          */ 
  809.         public List executeBatchDetailed() throws SQLException, BatchException { 
  810.             List answer = new ArrayList(); 
  811.             for (int i = 0, n = statementList.size(); i < n; i++) { 
  812.                 BatchResult br = (BatchResult) batchResultList.get(i); 
  813.                 PreparedStatement ps = (PreparedStatement) statementList.get(i); 
  814.                 try
  815.                     br.setUpdateCounts(ps.executeBatch()); 
  816.                 } catch (BatchUpdateException e) { 
  817.                     StringBuffer message = new StringBuffer(); 
  818.                     message.append("Sub batch number "); 
  819.                     message.append(i + 1); 
  820.                     message.append(" failed."); 
  821.                     if (i > 0) { 
  822.                         message.append(" "); 
  823.                         message.append(i); 
  824.                         message 
  825.                                 .append(" prior sub batch(s) completed successfully, but will be rolled back."); 
  826.                     } 
  827.                     throw new BatchException(message.toString(), e, answer, br 
  828.                             .getStatementId(), br.getSql()); 
  829.                 } 
  830.                 answer.add(br); 
  831.             } 
  832.             return answer; 
  833.         } 
  834.  
  835.         /**
  836.          * Close all the statements in the batch and clear all the statements
  837.          *
  838.          * @param sessionScope
  839.          */ 
  840.         public void cleanupBatch(SessionScope sessionScope) { 
  841.             for (int i = 0, n = statementList.size(); i < n; i++) { 
  842.                 PreparedStatement ps = (PreparedStatement) statementList.get(i); 
  843.                 closeStatement(sessionScope, ps); 
  844.             } 
  845.             currentSql = null
  846.             statementList.clear(); 
  847.             batchResultList.clear(); 
  848.             size = 0
  849.         } 
  850.     } 
  851.  
  852.     private void setupResultObjectFactory(StatementScope statementScope) { 
  853.         SqlMapClientImpl client = (SqlMapClientImpl) statementScope 
  854.                 .getSession().getSqlMapClient(); 
  855.         ResultObjectFactoryUtil.setResultObjectFactory(client 
  856.                 .getResultObjectFactory()); 
  857.         ResultObjectFactoryUtil.setStatementId(statementScope.getStatement() 
  858.                 .getId()); 
  859.     } 
/*
 *  Copyright 2004 Clinton Begin
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.ibatis.sqlmap.engine.execution;

import java.sql.BatchUpdateException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate;
import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;
import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactoryUtil;
import com.ibatis.sqlmap.engine.mapping.statement.DefaultRowHandler;
import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback;
import com.ibatis.sqlmap.engine.scope.ErrorContext;
import com.ibatis.sqlmap.engine.scope.SessionScope;
import com.ibatis.sqlmap.engine.scope.StatementScope;

/**
 * Class responsible for executing the SQL
 */
@SuppressWarnings ("unchecked")
public class SqlExecutor {

	private static final Log log = LogFactory.getLog(SqlExecutor.class);
	//
	// Constants
	//
	/**
	 * Constant to let us know not to skip anything
	 */
	public static final int NO_SKIPPED_RESULTS = 0;
	/**
	 * Constant to let us know to include all records
	 */
	public static final int NO_MAXIMUM_RESULTS = -999999;
	
	public SqlExecutor() {
		log.info("Custom class 'SqlExecutor' Initialization");
	}

	//
	// Public Methods
	//

	/**
	 * Execute an update
	 * 
	 * @param statementScope
	 *            - the request scope
	 * @param conn
	 *            - the database connection
	 * @param sql
	 *            - the sql statement to execute
	 * @param parameters
	 *            - the parameters for the sql statement
	 * @return - the number of records changed
	 * @throws SQLException
	 *             - if the update fails
	 */
	public int executeUpdate(StatementScope statementScope, Connection conn,
			String sql, Object[] parameters) throws SQLException {
		ErrorContext errorContext = statementScope.getErrorContext();
		errorContext.setActivity("executing update");
		errorContext.setObjectId(sql);
		PreparedStatement ps = null;
		setupResultObjectFactory(statementScope);
		int rows = 0;
		try {
			errorContext
					.setMoreInfo("Check the SQL Statement (preparation failed).");
			ps = prepareStatement(statementScope.getSession(), conn, sql);
			setStatementTimeout(statementScope.getStatement(), ps);
			errorContext
					.setMoreInfo("Check the parameters (set parameters failed).");
			statementScope.getParameterMap().setParameters(statementScope, ps,
					parameters);
			errorContext.setMoreInfo("Check the statement (update failed).");
			ps.execute();
			rows = ps.getUpdateCount();
		} finally {
			closeStatement(statementScope.getSession(), ps);
		}
		return rows;
	}

	/**
	 * Adds a statement to a batch
	 * 
	 * @param statementScope
	 *            - the request scope
	 * @param conn
	 *            - the database connection
	 * @param sql
	 *            - the sql statement
	 * @param parameters
	 *            - the parameters for the statement
	 * @throws SQLException
	 *             - if the statement fails
	 */
	public void addBatch(StatementScope statementScope, Connection conn,
			String sql, Object[] parameters) throws SQLException {
		Batch batch = (Batch) statementScope.getSession().getBatch();
		if (batch == null) {
			batch = new Batch();
			statementScope.getSession().setBatch(batch);
		}
		batch.addBatch(statementScope, conn, sql, parameters);
	}

	/**
	 * Execute a batch of statements
	 * 
	 * @param sessionScope
	 *            - the session scope
	 * @return - the number of rows impacted by the batch
	 * @throws SQLException
	 *             - if a statement fails
	 */
	public int executeBatch(SessionScope sessionScope) throws SQLException {
		int rows = 0;
		Batch batch = (Batch) sessionScope.getBatch();
		if (batch != null) {
			try {
				rows = batch.executeBatch();
			} finally {
				batch.cleanupBatch(sessionScope);
			}
		}
		return rows;
	}

	/**
	 * Execute a batch of statements
	 * 
	 * @param sessionScope
	 *            - the session scope
	 * @return - a List of BatchResult objects (may be null if no batch has been
	 *         initiated). There will be one BatchResult object in the list for
	 *         each sub-batch executed
	 * @throws SQLException
	 *             if a database access error occurs, or the drive does not
	 *             support batch statements
	 * @throws BatchException
	 *             if the driver throws BatchUpdateException
	 */
	public List executeBatchDetailed(SessionScope sessionScope)
			throws SQLException, BatchException {
		List answer = null;
		Batch batch = (Batch) sessionScope.getBatch();
		if (batch != null) {
			try {
				answer = batch.executeBatchDetailed();
			} finally {
				batch.cleanupBatch(sessionScope);
			}
		}
		return answer;
	}

	/**
	 * Long form of the method to execute a query
	 * 
	 * @param statementScope
	 *            - 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
	 */
//------------------------------- 分页代码重写(start) ------------------------------------//
	//重写executeQuery方法,首先判断是否分页查询,分页查询先将分页SQL语句构建,然后执行iBatis默认的查询
	public void executeQuery(StatementScope statementScope, Connection conn,
			String sql, Object[] parameters, int skipResults, int maxResults,
			RowHandlerCallback callback) throws SQLException {
		//取数据库产品名称
		String dbName = conn.getMetaData().getDatabaseProductName();
		
		int len = sql.length();
		
		//判断是否分页
		if ((skipResults != NO_SKIPPED_RESULTS || maxResults != NO_MAXIMUM_RESULTS)) {
			//根据数据库产品名称取对应的分页SQL语句
			sql = Dialect.getLimitString(dbName, sql, skipResults, maxResults);
			
			//分页语句是否存在
			if (sql.length() != len) {
				skipResults = NO_SKIPPED_RESULTS;
				maxResults = NO_MAXIMUM_RESULTS;
			}
        }
		iBatisExecuteQuery(statementScope, conn, sql, parameters, skipResults,
				maxResults, callback);
	}
	
	//iBatis包中默认的executeQuery方法
	private void iBatisExecuteQuery(StatementScope statementScope,
			Connection conn, String sql, Object[] parameters, int skipResults,
			int maxResults, RowHandlerCallback callback) throws SQLException {
		ErrorContext errorContext = statementScope.getErrorContext();
		errorContext.setActivity("executing query");
		errorContext.setObjectId(sql);
		PreparedStatement ps = null;
		ResultSet rs = null;
		setupResultObjectFactory(statementScope);
		try {
			errorContext
					.setMoreInfo("Check the SQL Statement (preparation failed).");
			Integer rsType = statementScope.getStatement().getResultSetType();
			if (rsType != null) {
				ps = prepareStatement(statementScope.getSession(), conn, sql,
						rsType);
			} else {
				ps = prepareStatement(statementScope.getSession(), conn, sql);
			}
			setStatementTimeout(statementScope.getStatement(), ps);
			Integer fetchSize = statementScope.getStatement().getFetchSize();
			if (fetchSize != null) {
				ps.setFetchSize(fetchSize.intValue());
			}
			errorContext
					.setMoreInfo("Check the parameters (set parameters failed).");
			statementScope.getParameterMap().setParameters(statementScope, ps,
					parameters);
			errorContext.setMoreInfo("Check the statement (query failed).");
			ps.execute();
			errorContext
					.setMoreInfo("Check the results (failed to retrieve results).");

			// Begin ResultSet Handling
			rs = handleMultipleResults(ps, statementScope, skipResults,
					maxResults, callback);
			// End ResultSet Handling
		} finally {
			try {
				closeResultSet(rs);
			} finally {
				closeStatement(statementScope.getSession(), ps);
			}
		}
	}
//-------------------- 分页代码重写(end) -------------------------------------//
	/**
	 * Execute a stored procedure that updates data
	 * 
	 * @param statementScope
	 *            - the request scope
	 * @param conn
	 *            - the database connection
	 * @param sql
	 *            - the SQL to call the procedure
	 * @param parameters
	 *            - the parameters for the procedure
	 * @return - the rows impacted by the procedure
	 * @throws SQLException
	 *             - if the procedure fails
	 */
	public int executeUpdateProcedure(StatementScope statementScope,
			Connection conn, String sql, Object[] parameters)
			throws SQLException {
		ErrorContext errorContext = statementScope.getErrorContext();
		errorContext.setActivity("executing update procedure");
		errorContext.setObjectId(sql);
		CallableStatement cs = null;
		setupResultObjectFactory(statementScope);
		int rows = 0;
		try {
			errorContext
					.setMoreInfo("Check the SQL Statement (preparation failed).");
			cs = prepareCall(statementScope.getSession(), conn, sql);
			setStatementTimeout(statementScope.getStatement(), cs);
			ParameterMap parameterMap = statementScope.getParameterMap();
			ParameterMapping[] mappings = parameterMap.getParameterMappings();
			errorContext
					.setMoreInfo("Check the output parameters (register output parameters failed).");
			registerOutputParameters(cs, mappings);
			errorContext
					.setMoreInfo("Check the parameters (set parameters failed).");
			parameterMap.setParameters(statementScope, cs, parameters);
			errorContext
					.setMoreInfo("Check the statement (update procedure failed).");
			cs.execute();
			rows = cs.getUpdateCount();
			errorContext
					.setMoreInfo("Check the output parameters (retrieval of output parameters failed).");
			retrieveOutputParameters(statementScope, cs, mappings, parameters,
					null);
		} finally {
			closeStatement(statementScope.getSession(), cs);
		}
		return rows;
	}

	/**
	 * Execute a stored procedure
	 * 
	 * @param statementScope
	 *            - the request scope
	 * @param conn
	 *            - the database connection
	 * @param sql
	 *            - the sql to call the procedure
	 * @param parameters
	 *            - the parameters for the procedure
	 * @param skipResults
	 *            - the number of results to skip
	 * @param maxResults
	 *            - the maximum number of results to return
	 * @param callback
	 *            - a row handler for processing the results
	 * @throws SQLException
	 *             - if the procedure fails
	 */
	public void executeQueryProcedure(StatementScope statementScope,
			Connection conn, String sql, Object[] parameters, int skipResults,
			int maxResults, RowHandlerCallback callback) throws SQLException {
		ErrorContext errorContext = statementScope.getErrorContext();
		errorContext.setActivity("executing query procedure");
		errorContext.setObjectId(sql);
		CallableStatement cs = null;
		ResultSet rs = null;
		setupResultObjectFactory(statementScope);
		try {
			errorContext
					.setMoreInfo("Check the SQL Statement (preparation failed).");
			Integer rsType = statementScope.getStatement().getResultSetType();
			if (rsType != null) {
				cs = prepareCall(statementScope.getSession(), conn, sql, rsType);
			} else {
				cs = prepareCall(statementScope.getSession(), conn, sql);
			}
			setStatementTimeout(statementScope.getStatement(), cs);
			Integer fetchSize = statementScope.getStatement().getFetchSize();
			if (fetchSize != null) {
				cs.setFetchSize(fetchSize.intValue());
			}
			ParameterMap parameterMap = statementScope.getParameterMap();
			ParameterMapping[] mappings = parameterMap.getParameterMappings();
			errorContext
					.setMoreInfo("Check the output parameters (register output parameters failed).");
			registerOutputParameters(cs, mappings);
			errorContext
					.setMoreInfo("Check the parameters (set parameters failed).");
			parameterMap.setParameters(statementScope, cs, parameters);
			errorContext
					.setMoreInfo("Check the statement (update procedure failed).");
			cs.execute();
			errorContext
					.setMoreInfo("Check the results (failed to retrieve results).");

			// Begin ResultSet Handling
			rs = handleMultipleResults(cs, statementScope, skipResults,
					maxResults, callback);
			// End ResultSet Handling
			errorContext
					.setMoreInfo("Check the output parameters (retrieval of output parameters failed).");
			retrieveOutputParameters(statementScope, cs, mappings, parameters,
					callback);

		} finally {
			try {
				closeResultSet(rs);
			} finally {
				closeStatement(statementScope.getSession(), cs);
			}
		}
	}

	private ResultSet handleMultipleResults(PreparedStatement ps,
			StatementScope statementScope, int skipResults, int maxResults,
			RowHandlerCallback callback) throws SQLException {
		ResultSet rs;
		rs = getFirstResultSet(statementScope, ps);
		if (rs != null) {
			handleResults(statementScope, rs, skipResults, maxResults, callback);
		}

		// Multiple ResultSet handling
		if (callback.getRowHandler() instanceof DefaultRowHandler) {
			MappedStatement statement = statementScope.getStatement();
			DefaultRowHandler defaultRowHandler = ((DefaultRowHandler) callback
					.getRowHandler());
			if (statement.hasMultipleResultMaps()) {
				List multipleResults = new ArrayList();
				multipleResults.add(defaultRowHandler.getList());
				ResultMap[] resultMaps = statement.getAdditionalResultMaps();
				int i = 0;
				while (moveToNextResultsSafely(statementScope, ps)) {
					if (i >= resultMaps.length)
						break;
					ResultMap rm = resultMaps[i];
					statementScope.setResultMap(rm);
					rs = ps.getResultSet();
					DefaultRowHandler rh = new DefaultRowHandler();
					handleResults(statementScope, rs, skipResults, maxResults,
							new RowHandlerCallback(rm, null, rh));
					multipleResults.add(rh.getList());
					i++;
				}
				defaultRowHandler.setList(multipleResults);
				statementScope.setResultMap(statement.getResultMap());
			} else {
				while (moveToNextResultsSafely(statementScope, ps))
					;
			}
		}
		// End additional ResultSet handling
		return rs;
	}

	private ResultSet getFirstResultSet(StatementScope scope, Statement stmt)
			throws SQLException {
		ResultSet rs = null;
		boolean hasMoreResults = true;
		while (hasMoreResults) {
			rs = stmt.getResultSet();
			if (rs != null) {
				break;
			}
			hasMoreResults = moveToNextResultsIfPresent(scope, stmt);
		}
		return rs;
	}

	private boolean moveToNextResultsIfPresent(StatementScope scope,
			Statement stmt) throws SQLException {
		boolean moreResults;
		// This is the messed up JDBC approach for determining if there are more
		// results
		moreResults = !(((moveToNextResultsSafely(scope, stmt) == false) && (stmt
				.getUpdateCount() == -1)));
		return moreResults;
	}

	private boolean moveToNextResultsSafely(StatementScope scope, Statement stmt)
			throws SQLException {
		if (forceMultipleResultSetSupport(scope)
				|| stmt.getConnection().getMetaData()
						.supportsMultipleResultSets()) {
			return stmt.getMoreResults();
		}
		return false;
	}

	private boolean forceMultipleResultSetSupport(StatementScope scope) {
		return ((SqlMapClientImpl) scope.getSession().getSqlMapClient())
				.getDelegate().isForceMultipleResultSetSupport();
	}

	private void handleResults(StatementScope statementScope, ResultSet rs,
			int skipResults, int maxResults, RowHandlerCallback callback)
			throws SQLException {
		try {
			statementScope.setResultSet(rs);
			ResultMap resultMap = statementScope.getResultMap();
			if (resultMap != null) {
				// Skip Results
				if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
					if (skipResults > 0) {
						rs.absolute(skipResults);
					}
				} else {
					for (int i = 0; i < skipResults; i++) {
						if (!rs.next()) {
							return;
						}
					}
				}

				// Get Results
				int resultsFetched = 0;
				while ((maxResults == SqlExecutor.NO_MAXIMUM_RESULTS || resultsFetched < maxResults)
						&& rs.next()) {
					Object[] columnValues = resultMap.resolveSubMap(
							statementScope, rs).getResults(statementScope, rs);
					callback.handleResultObject(statementScope, columnValues,
							rs);
					resultsFetched++;
				}
			}
		} finally {
			statementScope.setResultSet(null);
		}
	}

	private void retrieveOutputParameters(StatementScope statementScope,
			CallableStatement cs, ParameterMapping[] mappings,
			Object[] parameters, RowHandlerCallback callback)
			throws SQLException {
		for (int i = 0; i < mappings.length; i++) {
			ParameterMapping mapping = ((ParameterMapping) mappings[i]);
			if (mapping.isOutputAllowed()) {
				if ("java.sql.ResultSet".equalsIgnoreCase(mapping
						.getJavaTypeName())) {
					ResultSet rs = (ResultSet) cs.getObject(i + 1);
					ResultMap resultMap;
					if (mapping.getResultMapName() == null) {
						resultMap = statementScope.getResultMap();
						handleOutputParameterResults(statementScope, resultMap,
								rs, callback);
					} else {
						SqlMapClientImpl client = (SqlMapClientImpl) statementScope
								.getSession().getSqlMapClient();
						resultMap = client.getDelegate().getResultMap(
								mapping.getResultMapName());
						DefaultRowHandler rowHandler = new DefaultRowHandler();
						RowHandlerCallback handlerCallback = new RowHandlerCallback(
								resultMap, null, rowHandler);
						handleOutputParameterResults(statementScope, resultMap,
								rs, handlerCallback);
						parameters[i] = rowHandler.getList();
					}
					rs.close();
				} else {
					parameters[i] = mapping.getTypeHandler().getResult(cs,
							i + 1);
				}
			}
		}
	}

	private void registerOutputParameters(CallableStatement cs,
			ParameterMapping[] mappings) throws SQLException {
		for (int i = 0; i < mappings.length; i++) {
			ParameterMapping mapping = ((ParameterMapping) mappings[i]);
			if (mapping.isOutputAllowed()) {
				if (null != mapping.getTypeName()
						&& !mapping.getTypeName().equals("")) { // @added
					cs.registerOutParameter(i + 1, mapping.getJdbcType(),
							mapping.getTypeName());
				} else {
					if (mapping.getNumericScale() != null
							&& (mapping.getJdbcType() == Types.NUMERIC || mapping
									.getJdbcType() == Types.DECIMAL)) {
						cs.registerOutParameter(i + 1, mapping.getJdbcType(),
								mapping.getNumericScale().intValue());
					} else {
						cs.registerOutParameter(i + 1, mapping.getJdbcType());
					}
				}
			}
		}
	}

	private void handleOutputParameterResults(StatementScope statementScope,
			ResultMap resultMap, ResultSet rs, RowHandlerCallback callback)
			throws SQLException {
		ResultMap orig = statementScope.getResultMap();
		try {
			statementScope.setResultSet(rs);
			if (resultMap != null) {
				statementScope.setResultMap(resultMap);

				// Get Results
				while (rs.next()) {
					Object[] columnValues = resultMap.resolveSubMap(
							statementScope, rs).getResults(statementScope, rs);
					callback.handleResultObject(statementScope, columnValues,
							rs);
				}
			}
		} finally {
			statementScope.setResultSet(null);
			statementScope.setResultMap(orig);
		}
	}

	/**
	 * Clean up any batches on the session
	 * 
	 * @param sessionScope
	 *            - the session to clean up
	 */
	public void cleanup(SessionScope sessionScope) {
		Batch batch = (Batch) sessionScope.getBatch();
		if (batch != null) {
			batch.cleanupBatch(sessionScope);
			sessionScope.setBatch(null);
		}
	}

	private PreparedStatement prepareStatement(SessionScope sessionScope,
			Connection conn, String sql, Integer rsType) throws SQLException {
		SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope
				.getSqlMapExecutor()).getDelegate();
		if (sessionScope.hasPreparedStatementFor(sql)) {
			return sessionScope.getPreparedStatement((sql));
		} else {
			PreparedStatement ps = conn.prepareStatement(sql,
					rsType.intValue(), ResultSet.CONCUR_READ_ONLY);
			sessionScope.putPreparedStatement(delegate, sql, ps);
			return ps;
		}
	}

	private CallableStatement prepareCall(SessionScope sessionScope,
			Connection conn, String sql, Integer rsType) throws SQLException {
		SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope
				.getSqlMapExecutor()).getDelegate();
		if (sessionScope.hasPreparedStatementFor(sql)) {
			return (CallableStatement) sessionScope.getPreparedStatement((sql));
		} else {
			CallableStatement cs = conn.prepareCall(sql, rsType.intValue(),
					ResultSet.CONCUR_READ_ONLY);
			sessionScope.putPreparedStatement(delegate, sql, cs);
			return cs;
		}
	}

	private static PreparedStatement prepareStatement(
			SessionScope sessionScope, Connection conn, String sql)
			throws SQLException {
		SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope
				.getSqlMapExecutor()).getDelegate();
		if (sessionScope.hasPreparedStatementFor(sql)) {
			return sessionScope.getPreparedStatement((sql));
		} else {
			PreparedStatement ps = conn.prepareStatement(sql);
			sessionScope.putPreparedStatement(delegate, sql, ps);
			return ps;
		}
	}

	private CallableStatement prepareCall(SessionScope sessionScope,
			Connection conn, String sql) throws SQLException {
		SqlMapExecutorDelegate delegate = ((SqlMapClientImpl) sessionScope
				.getSqlMapExecutor()).getDelegate();
		if (sessionScope.hasPreparedStatementFor(sql)) {
			return (CallableStatement) sessionScope.getPreparedStatement((sql));
		} else {
			CallableStatement cs = conn.prepareCall(sql);
			sessionScope.putPreparedStatement(delegate, sql, cs);
			return cs;
		}
	}

	private static void closeStatement(SessionScope sessionScope,
			PreparedStatement ps) {
		if (ps != null) {
			if (!sessionScope.hasPreparedStatement(ps)) {
				try {
					ps.close();
				} catch (SQLException e) {
					// ignore
				}
			}
		}
	}

	/**
	 * @param rs
	 */
	private static void closeResultSet(ResultSet rs) {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				// ignore
			}
		}
	}

	private static void setStatementTimeout(MappedStatement mappedStatement,
			Statement statement) throws SQLException {
		if (mappedStatement.getTimeout() != null) {
			statement.setQueryTimeout(mappedStatement.getTimeout().intValue());
		}
	}

	//
	// Inner Classes
	//

	private static class Batch {
		private String currentSql;
		private List statementList = new ArrayList();
		private List batchResultList = new ArrayList();
		private int size;

		/**
		 * Create a new batch
		 */
		public Batch() {
			this.size = 0;
		}

		/**
		 * Getter for the batch size
		 * 
		 * @return - the batch size
		 */
		public int getSize() {
			return size;
		}

		/**
		 * Add a prepared statement to the batch
		 * 
		 * @param statementScope
		 *            - the request scope
		 * @param conn
		 *            - the database connection
		 * @param sql
		 *            - the SQL to add
		 * @param parameters
		 *            - the parameters for the SQL
		 * @throws SQLException
		 *             - if the prepare for the SQL fails
		 */
		public void addBatch(StatementScope statementScope, Connection conn,
				String sql, Object[] parameters) throws SQLException {
			PreparedStatement ps = null;
			if (currentSql != null && currentSql.equals(sql)) {
				int last = statementList.size() - 1;
				ps = (PreparedStatement) statementList.get(last);
			} else {
				ps = prepareStatement(statementScope.getSession(), conn, sql);
				setStatementTimeout(statementScope.getStatement(), ps);
				currentSql = sql;
				statementList.add(ps);
				batchResultList.add(new BatchResult(statementScope
						.getStatement().getId(), sql));
			}
			statementScope.getParameterMap().setParameters(statementScope, ps,
					parameters);
			ps.addBatch();
			size++;
		}

		/**
		 * TODO (Jeff Butler) - maybe this method should be deprecated in some
		 * release, and then removed in some even later release.
		 * executeBatchDetailed gives much more complete information. <p/>
		 * Execute the current session's batch
		 * 
		 * @return - the number of rows updated
		 * @throws SQLException
		 *             - if the batch fails
		 */
		public int executeBatch() throws SQLException {
			int totalRowCount = 0;
			for (int i = 0, n = statementList.size(); i < n; i++) {
				PreparedStatement ps = (PreparedStatement) statementList.get(i);
				int[] rowCounts = ps.executeBatch();
				for (int j = 0; j < rowCounts.length; j++) {
					if (rowCounts[j] == Statement.SUCCESS_NO_INFO) {
						// do nothing
					} else if (rowCounts[j] == Statement.EXECUTE_FAILED) {
						throw new SQLException(
								"The batched statement at index " + j
										+ " failed to execute.");
					} else {
						totalRowCount += rowCounts[j];
					}
				}
			}
			return totalRowCount;
		}

		/**
		 * Batch execution method that returns all the information the driver
		 * has to offer.
		 * 
		 * @return a List of BatchResult objects
		 * @throws BatchException
		 *             (an SQLException sub class) if any nested batch fails
		 * @throws SQLException
		 *             if a database access error occurs, or the drive does not
		 *             support batch statements
		 * @throws BatchException
		 *             if the driver throws BatchUpdateException
		 */
		public List executeBatchDetailed() throws SQLException, BatchException {
			List answer = new ArrayList();
			for (int i = 0, n = statementList.size(); i < n; i++) {
				BatchResult br = (BatchResult) batchResultList.get(i);
				PreparedStatement ps = (PreparedStatement) statementList.get(i);
				try {
					br.setUpdateCounts(ps.executeBatch());
				} catch (BatchUpdateException e) {
					StringBuffer message = new StringBuffer();
					message.append("Sub batch number ");
					message.append(i + 1);
					message.append(" failed.");
					if (i > 0) {
						message.append(" ");
						message.append(i);
						message
								.append(" prior sub batch(s) completed successfully, but will be rolled back.");
					}
					throw new BatchException(message.toString(), e, answer, br
							.getStatementId(), br.getSql());
				}
				answer.add(br);
			}
			return answer;
		}

		/**
		 * Close all the statements in the batch and clear all the statements
		 * 
		 * @param sessionScope
		 */
		public void cleanupBatch(SessionScope sessionScope) {
			for (int i = 0, n = statementList.size(); i < n; i++) {
				PreparedStatement ps = (PreparedStatement) statementList.get(i);
				closeStatement(sessionScope, ps);
			}
			currentSql = null;
			statementList.clear();
			batchResultList.clear();
			size = 0;
		}
	}

	private void setupResultObjectFactory(StatementScope statementScope) {
		SqlMapClientImpl client = (SqlMapClientImpl) statementScope
				.getSession().getSqlMapClient();
		ResultObjectFactoryUtil.setResultObjectFactory(client
				.getResultObjectFactory());
		ResultObjectFactoryUtil.setStatementId(statementScope.getStatement()
				.getId());
	}
}


Dialect.java

Java代码 复制代码 收藏代码
  1. package com.ibatis.sqlmap.engine.execution; 
  2.  
  3. public class Dialect { 
  4.     private static final String SQL_END_DELIMITER = ";"
  5.  
  6.     public static String getLimitString(String dbName, String sql, int offset, 
  7.             int limit) { 
  8.         String limitString = sql; 
  9.         if (dbName.toLowerCase().indexOf("mysql") != -1) { 
  10.             limitString = getMysqlLimitString(sql, offset, limit); 
  11.         } 
  12.         if (dbName.toLowerCase().indexOf("microsoft sql server") != -1) { 
  13.             limitString = getMssqlLimitString(sql, offset, limit); 
  14.         } 
  15.         if (dbName.toLowerCase().indexOf("oracle") != -1) { 
  16.             limitString = getOracleLimitString(sql, offset, limit); 
  17.         } 
  18.         if (dbName.toLowerCase().indexOf("db2") != -1) { 
  19.             limitString = getDB2LimitString(sql, offset, limit); 
  20.         } 
  21.          
  22.         return limitString; 
  23.     } 
  24.  
  25.     private static String getMysqlLimitString(String sql, int offset, int limit) { 
  26.         sql = trim(sql); 
  27.         StringBuffer sb = new StringBuffer(sql.length() + 20); 
  28.         sb.append(sql); 
  29.         if (offset > 0) { 
  30.             sb.append(" limit ").append(offset).append(',').append(limit); 
  31.         } else
  32.             sb.append(" limit ").append(limit); 
  33.         } 
  34.         return sb.toString(); 
  35.     } 
  36.  
  37.     private static String getOracleLimitString(String sql, int offset, int limit) { 
  38.         sql = trim(sql); 
  39.         StringBuffer sb = new StringBuffer(sql.length() + 100); 
  40.         if (offset > 0) { 
  41.             sb.append("select * from ( select row_.*, rownum rownum_ from ( "
  42.                     .append(sql).append(" ) row_ where rownum <= ").append( 
  43.                             offset + limit).append(") where rownum_ > "
  44.                     .append(offset); 
  45.         } else
  46.             sb.append("select * from ( ").append(sql).append( 
  47.                     " ) where rownum <= ").append(limit); 
  48.         } 
  49.         return sb.toString(); 
  50.     } 
  51.  
  52.     private static String getMssqlLimitString(String sql, int offset, int limit) { 
  53.         return null
  54.     } 
  55.      
  56.     private static String getDB2LimitString(String sql, int offset, int limit) {         
  57.         return null
  58.     } 
  59.  
  60.     private static String trim(String sql) { 
  61.         sql = sql.trim(); 
  62.         if (sql.endsWith(SQL_END_DELIMITER)) { 
  63.             sql = sql.substring(0, sql.length() - 1 
  64.                     - SQL_END_DELIMITER.length()); 
  65.         } 
  66.         return sql; 
  67.     } 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值