- 浏览: 932437 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (251)
- WebService (17)
- IBatis (22)
- Hibernate (1)
- SpringMVC - 基础篇 (32)
- Spring (15)
- Java (11)
- JVM及调优 - 基础篇 (4)
- 集群 (14)
- 数据库 (17)
- WebSphere (5)
- 多线程 (4)
- 集合、容器 (2)
- DB Pool (1)
- Power Designer (5)
- Maven基础 (5)
- JS (14)
- WEB 前端 (5)
- 实用小工具 (17)
- 社会、人 (2)
- 乱七八糟 (18)
- ASM&CGLIB - 基础篇 (12)
- 缓存 (1)
- 性能 (1)
- 设计之殇 (1)
- 分布式事务 (1)
- 单点登录 (11)
- 分布式 Session (4)
- Memcached - 基础篇 (6)
最新评论
-
一笑_奈何:
楼主写的还真行不错。
扫盲贴 - J2EE集群之JNDI集群实现 -
xuezhongyu01:
博主写的很详细,但最后还是没明白,最后调用BasicDataS ...
Spring中的destroy-method方法 -
Mr梁:
commons-fileupload.jar commons- ...
SpringMVC 中文件上传 MultipartResolver -
Eywa:
总结的很不错
ORACLE CASE WHEN 及 SELECT CASE WHEN的用法 -
TryRelax:
fastjson 比 jackson 好用吧?
Spring MVC Jackson DateFormat
感谢 http://www.iteye.com/topic/544765;http://www.iteye.com/topic/566605
首先看一下iBatis的分页代码是怎么执行的
iBatis中,具体负责执行sql的类是 com.ibatis.sqlmap.engine.execution.SqlExecutor。
负责分页查询的方法是executeQuery —>handleMultipleResults —> handleResults。handleResults方法的源码如下:
private void handleResults(RequestScope request, ResultSet rs, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { try { request.setResultSet(rs); ResultMap resultMap = request.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(request, rs).getResults(request, rs); callback.handleResultObject(request, columnValues, rs); resultsFetched++; } } } finally { request.setResultSet(null); } }
从代码中可以看出iBatis分页查询的逻辑是首先判断ResulteSet的类型,
如果ResultSet的类型是 ResultSet.TYPE_FORWARD_ONLY,则使用ResultSet对象的next()方法,一步一步地移动游标到要取的第一条记录的位置,然后再采用next()方法取出一页的数据;
如果ResultSet的类型不是ResultSet.TYPE_FORWARD_ONLY,则采用 ResultSet对象的absolute()方法,移动游标到要取的第一条记录的位置,然后再采用next()方法取出一页的数据。
ResultSet的类型,是在iBatis的配置文件中配置的,如: <select id="queryAllUser" resultMap="user" resultSetType="FORWARD_ONLY"> select id,name from user_tab </select>
其中resultSetType的可选值为FORWARD_ONLY | SCROLL_INSENSITIVE | SCROLL_SENSITIVE,
如果没有配置,默认值为FORWARD_ONLY,FORWARD_ONLY类型的ResultSet 不支持absolute方法,所以是通过next方法定位的。
一般情况下,我们都使用FORWARD_ONLY类型的ResultSet,SCROLL类型ResultSet的优点是可向前,向后滚动,并支持精确定位(absolute),但缺点是把结果集全部加载进缓存(如果查询是从100万条数据开始取100条,会把前100万条数据也加载进缓存),容易造成内存溢出,性能也很差,除非必要,一般不使用。
可见,iBatis的分页完全依赖于JDBC ResultSet的next方法或absolute方法来实现。
而Hibernate在分页查询方面,比iBatis要好很多,Hibernate可以根据不同的数据库,对sql做不同的优化加工,然后再执行优化后的sql。
比如,对于Oracle数据库来说,原始sql为select * form user_tab, 从1000001条开始取100条,则hibernate加工后的sql为:
select * from (select row_.*, rownum rownum_ from (SELECT * FROM user_tab) row_ where rownum <= 1000100) where rownum_ > 1000000
写一个程序,对比一下两种方式下的查询效率。程序如下:
public class Test{ public static void main(String[] args) throws Exception { Class.forName("oracle.jdbc.driver.OracleDriver"); Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:db", "db", "xwdb"); long a = System.currentTimeMillis(); testIbatisPageQuery(conn); //testHibernatePageQuery(conn); long b = System.currentTimeMillis(); System.out.println(b-a); } public static void testIbatisPageQuery(Connection conn) throws Exception{ String sql = "SELECT * FROM user_tab "; Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); ResultSet rs = stmt.executeQuery(sql); int j=0; //游标移动到1000001条数据的位置 while(rs.next() && j++<1000000){ } int i=0; //依次取出100条数据 while(rs.next() && i++<100){ } } public static void testHibernatePageQuery(Connection conn) throws Exception{ String sql = "SELECT * FROM user_tab "; StringBuffer pagingSelect = new StringBuffer( sql.length()+100 ); pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( "); pagingSelect.append(sql); pagingSelect.append(" ) row_ where rownum <= 1000100) where rownum_ > 1000000"); Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); ResultSet rs = stmt.executeQuery(pagingSelect.toString()); while(rs.next()){ } } }
发现testIbatisPageQuery需要执行十几秒,而testHibernatePageQuery仅需要执行零点几秒,差异很大。
而如果改成从1000条开始取100条,甚至更靠前,则2者的差别是非常小的。
综上所述,如果系统中查询的数据量很大,并且用户会选择查询非常靠后的数据,那么我们就应该替换iBatis的分页实现,如果不存在这种情况,那我们就不需要替换iBatis的分页实现,一般情况下,用户不可能去查询那么靠后的页,这也是iBatis一直不修改分页实现的原因吧。
如果我们选择替换的话,有三种办法,
一种是自己写一个类,继承iBatis的SqlExecutor,然后把这个类注入到 com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient中,由于SqlExecutor是 ExtendedSqlMapClient的私有变量,没有public类型的set方法,所以需要采用reflect机制注入;
第二种办法是弃用iBatis的分页查询方法 queryForList(String sql,Object obj,int maxResult,int skipResult),而用普通查询方法,queryForList(String sql,Object obj)。只不过把maxResult和skipResult都作为obj的变量传到sql里去。如下:
<select id="queryAllUser" resultMap="user"> select * from (select row_.*, rownum rownum_ from (SELECT * FROM user_tab) row_ where rownum <= #_maxResult#) where rownum_ > #_skipResult# </select>
第三种方法是在自己的工程里写一个和iBatis的SqlExecutor的包名和类名完全一样的类,web工程中,WEB-INF/classes下的java类,先于 WEB-INF/lib下jar包的加载,所以就巧妙了覆盖了iBatis的SqlExecutor类;
这种方式可行是因为
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
/* * 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
package com.ibatis.sqlmap.engine.execution; public class Dialect { private static final String SQL_END_DELIMITER = ";"; public static String getLimitString(String dbName, String sql, int offset, int limit) { String limitString = sql; if (dbName.toLowerCase().indexOf("mysql") != -1) { limitString = getMysqlLimitString(sql, offset, limit); } if (dbName.toLowerCase().indexOf("microsoft sql server") != -1) { limitString = getMssqlLimitString(sql, offset, limit); } if (dbName.toLowerCase().indexOf("oracle") != -1) { limitString = getOracleLimitString(sql, offset, limit); } if (dbName.toLowerCase().indexOf("db2") != -1) { limitString = getDB2LimitString(sql, offset, limit); } return limitString; } private static String getMysqlLimitString(String sql, int offset, int limit) { sql = trim(sql); StringBuffer sb = new StringBuffer(sql.length() + 20); sb.append(sql); if (offset > 0) { sb.append(" limit ").append(offset).append(',').append(limit); } else { sb.append(" limit ").append(limit); } return sb.toString(); } private static String getOracleLimitString(String sql, int offset, int limit) { sql = trim(sql); StringBuffer sb = new StringBuffer(sql.length() + 100); if (offset > 0) { sb.append("select * from ( select row_.*, rownum rownum_ from ( ") .append(sql).append(" ) row_ where rownum <= ").append( offset + limit).append(") where rownum_ > ") .append(offset); } else { sb.append("select * from ( ").append(sql).append( " ) where rownum <= ").append(limit); } return sb.toString(); } private static String getMssqlLimitString(String sql, int offset, int limit) { return null; } private static String getDB2LimitString(String sql, int offset, int limit) { return null; } private static String trim(String sql) { sql = sql.trim(); if (sql.endsWith(SQL_END_DELIMITER)) { sql = sql.substring(0, sql.length() - 1 - SQL_END_DELIMITER.length()); } return sql; } }
发表评论
-
iBATIS缓存
2011-12-12 21:33 1165为了提高应用程序性 ... -
iBatis批处理(batch)
2011-09-05 23:47 6957spring集成了ibatis的批量提交的功能,我们只要调用A ... -
一个Spring+iBatis框架进行batch处理的问题
2011-09-05 23:23 1623在使用org.springframework.jdbc.dat ... -
ibatis 注意点
2011-08-08 19:28 1383insert,update,delete 返回值 inser ... -
ibatis 之 动态SQL查询(dynamic )
2011-06-12 12:13 2288映射文件: <select id=" ... -
ibatis 之 复杂类型集合的属性
2011-06-12 12:10 2149Result Map还可以装入代表复杂类型对象集合(List) ... -
ibatis 之 复杂类型属性(即自定义类型的属性)
2011-06-12 11:54 3451复杂类型用以表示在数 ... -
ibatis 之 java.util.Map作为parameterClass和resultClass
2011-06-12 11:21 51641.Map作为parameterClass 映射 ... -
ibatis Tips 之 resultMap
2011-05-29 21:04 1210转载:http://xulongfa.iteye.com/bl ... -
ibatis Tips之parameterMap
2011-05-29 21:03 1343转载:http://xulongfa.iteye.com/bl ... -
iBatis查询API
2011-05-29 12:34 1857转载:http://sarin.iteye.com/blog/ ... -
iBatis查询select详解
2011-05-29 12:20 2219转载:http://sarin.iteye.com/blog/ ... -
ibatis 表与表的关联查询
2011-05-22 15:04 1267ibatis高级特性,处理表与表之间的关联。ibatis中,提 ... -
ibatis 动态映射机制
2011-05-22 14:15 1458对于这个组合查询页 ... -
sqlMapConfig.xml配置文件详解
2011-05-22 13:04 3554sqlMapConfig.xml配置文件详解: X ... -
ibatis缓存
2011-05-22 12:52 1364iBatis的缓存配置比较简单易懂,以我使用的iBati ... -
ibatis resultclass "java.util.hashmap" 缓存问题
2011-05-22 12:13 1523在做ibatis项目过程中遇到如下样式动态查询 <se ... -
ibatis # $区别
2011-05-22 11:55 14401、#可以进行预编译,进行类型匹配,#变量名# 会转化为 j ... -
iBATIS入门示例及注释
2011-05-08 18:20 1798工程的结构: 一、SqlMapConf ... -
iBATIS 三个版本小细节对比
2011-05-08 16:12 1205iBATIS 三个版本小细节对比 sqlMapConfig ...
相关推荐
在IT行业中,分页是数据库查询的一个重要特性,特别是在数据量庞大的系统中,它能够有效地帮助用户管理和浏览信息。Ibatis,作为一个轻量级的Java持久层框架,提供了灵活的SQL映射机制,自然也支持分页查询。本文将...
使用Oracle的分页功能,可以高效地处理大量数据的查询,同时,其强大的数据类型支持附件的存储。 5. **分页搜索**:在Web应用中,分页搜索是提升用户体验的重要手段。通过在后台实现SQL的分页查询,Struts2和Spring...
Ibatis 是一款轻量级的Java持久层框架,它提供了SQL映射功能,使得开发者能够将SQL语句与Java代码分离,从而实现更灵活的数据访问。在2.3.4这个版本中,Ibatis 提供了数据库无关的分页功能,这是一种在不依赖特定...
在处理大量数据时,分页是提高系统性能和用户体验的关键。 在描述中提到了一个博客链接,虽然具体内容没有给出,但通常博主会分享关于iBATIS分页实现的详细步骤、常见问题以及可能的解决方案。iBATIS的分页实现主要...
同时,可以结合索引来进一步优化查询性能,尤其是在处理大数据量时。此外,Oracle的Materialized Views(物化视图)可以在后台预先计算并存储查询结果,提高查询速度,但需权衡额外的存储空间和更新延迟。 总的来说...
在处理大量数据时,分页查询是必不可少的功能,可以有效地减少数据库负载并提高用户体验。Ibatis.NET提供了分页查询的实现,下面我们将深入探讨如何在Ibatis.NET中实现分页。 首先,理解分页的基本概念。分页通常...
在处理大量数据时,为了提高用户体验,分页显示数据变得至关重要。本篇将详细讲解如何利用Ibatis实现分页技术。 一、Ibatis简介 Ibatis是由Clinton Begin创建的一个SQL映射框架,它允许开发者将SQL语句直接写在配置...
在IT行业中,分页是一种常见的数据处理技术,特别是在Web应用中,用于提高用户体验,避免一次性加载过多数据导致页面响应变慢。本项目基于ibatis框架实现了分页功能,覆盖了从底层数据库操作到页面展示的完整流程,...
在开发Web应用时,数据管理是一项关键任务,尤其是在处理大量数据时。本教程将深入探讨如何使用Spring、iBatis和JSP这三个组件来集成实现数据库查询和分页功能。这三个技术结合,能够构建出高效、灵活且易于维护的...
分页是Web应用中常见的需求,它能帮助用户更有效地浏览大量数据。在iBATIS中实现分页功能,我们可以利用其提供的PageHelper插件或自定义标签来实现。 标题"ibatis分页功能"指的就是如何在iBATIS框架中实现数据库...
Ibatis,作为一款轻量级的Java持久层框架,虽然功能强大,但在默认情况下,其分页方式是逻辑分页,即先查询所有数据,然后在应用程序层面进行分页处理,这种方式对于大数据量的查询来说,无疑会消耗大量的内存和CPU...
而Ibatis是一个轻量级的Java持久层框架,它允许开发者将SQL语句直接写在配置文件中,与ORM(对象关系映射)框架相比,提供了更大的灵活性。 在这个项目中,"SSI整合"指的是开发者将SSI技术应用到项目中,可能是在...
总之,通过以上方法,我们可以实现在不修改iBatis源码的前提下,让iBatis支持类似Hibernate的物理分页,提高查询效率,尤其在大数据量的场景下,这种优化尤为关键。不过,需要注意的是,不同的数据库系统对物理分页...
在IT行业中,数据库查询的效率和用户体验息息相关,尤其是在数据量庞大的场景下,分页功能显得尤为重要。本知识点将深入探讨如何在Struts2框架中结合iBatis实现基于Freemarker模板的分页功能。 首先,我们需要理解...
### MySQL、JDBC详解及与iBatis对比 #### 一、MySQL基本操作 MySQL作为一款广泛使用的开源关系型数据库管理系统,在IT行业中占有极其重要的地位。对于开发人员来说,掌握MySQL的基本操作至关重要。 ##### 1. 增删...
在IT行业中,数据库查询是日常开发中的重要环节,特别是对于大数据量的系统,分页查询是必不可少的功能。MyBatis作为一个轻量级的持久层框架,提供了强大的SQL映射和数据访问能力,但在处理大量数据时,一次性加载...
分页是Web应用中常见的需求,尤其是在处理大数据量时,避免一次性加载所有数据导致性能下降。在Ibatis和Mybatis中,分页通常通过在SQL查询语句中添加LIMIT和OFFSET子句来实现。在Mybatis中,可以通过设置Mapper XML...
本篇文章将深入探讨如何在Xwork和iBatis的集成应用中实现分页功能,让开发者能够更高效地处理大量数据。 首先,让我们了解什么是分页。分页是网页显示大量数据时常用的一种技术,它将结果集分割成若干小部分(页)...
Ibatis 是一款轻量级的持久层框架,它与 JDBC 集成,但比 JDBC 更加方便,更易于管理数据库操作。在多表查询中,Ibatis 提供了多种方式来处理复杂的关联查询,包括一对一、一对多、多对一和多对多等关系。在这个例子...
而"iBaits按条件查询及分页功能"进一步强调了这个资源关注的重点,即利用iBatis实现基于用户输入条件的查询,并结合分页技术优化大数据量的展示。 总的来说,这个资源适合对半自动化持久层框架感兴趣的开发者,尤其...