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.  
分享到:
评论

你可能感兴趣的:(apache,spring,sql,Web,ibatis)