- 浏览: 483895 次
- 性别:
- 来自: 武汉
最新评论
-
zyzyzy123:
请问有工程吗,我现在正在实现打电话的功能,但是一直不通,怀疑是 ...
实用的java 串口通信程序 -
wuhaitong:
引用[img][/img][*][url][/url] ...
jbpm -
迷糊_le:
maven命令, 蛮好的,谢谢
maven eclipse -
Wuaner:
不错的文章 , 谢谢分享!
Hadoop -
yuqihengsheng:
strong 很细
HighLighter
一直以来ibatis 的分页 都是通过滚动ResultSet实现的,应该算是逻辑分页 吧。逻辑分页 虽然能很干净地独立于特定数据库,但效率在多数情况下不及特定数据库支持的物理分页 ,而hibernate的分页 则是直接组装sql,充分利用了特定数据库的分页 机制,效率相对较高。本文讲述的就是如何在不重新编译ibatis 源码的前提下,为ibatis 引入hibernate式的物理分页 机制。
基本思路就是找到ibatis 执行sql的地方,截获sql并重新组装sql。通过分析ibatis 源码知道,最终负责执行sql的类是 com.ibatis .sqlmap.engine.execution.SqlExecutor,此类没有实现任何接口,这多少有点遗憾,因为接口是相对稳定契约,非大的版本更新,接口一般是不会变的,而类就相对易变一些,所以这里的代码只能保证对当前版本(2.1.7)的ibatis 有效。下面是 SqlExecutor执行查询的方法:
- /**
- * Long form of the method to execute a query
- *
- * @param request - the request scope
- * @param conn - the database connection
- * @param sql - the SQL statement to execute
- * @param parameters - the parameters for the statement
- * @param skipResults - the number of results to skip
- * @param maxResults - the maximum number of results to return
- * @param callback - the row handler for the query
- *
- * @throws SQLException - if the query fails
- */
- public void executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters,
- int skipResults, int maxResults, RowHandlerCallback callback)
- throws SQLException {
- ErrorContext errorContext = request.getErrorContext();
- errorContext.setActivity("executing query" );
- errorContext.setObjectId(sql);
- PreparedStatement ps = null ;
- ResultSet rs = null ;
- try {
- errorContext.setMoreInfo("Check the SQL Statement (preparation failed)." );
- Integer rsType = request.getStatement().getResultSetType();
- if (rsType != null ) {
- ps = conn.prepareStatement(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY);
- } else {
- ps = conn.prepareStatement(sql);
- }
- Integer fetchSize = request.getStatement().getFetchSize();
- if (fetchSize != null ) {
- ps.setFetchSize(fetchSize.intValue());
- }
- errorContext.setMoreInfo("Check the parameters (set parameters failed)." );
- request.getParameterMap().setParameters(request, ps, parameters);
- errorContext.setMoreInfo("Check the statement (query failed)." );
- ps.execute();
- rs = getFirstResultSet(ps);
- if (rs != null ) {
- errorContext.setMoreInfo("Check the results (failed to retrieve results)." );
- handleResults(request, rs, skipResults, maxResults, callback);
- }
- // clear out remaining results
- while (ps.getMoreResults());
- } finally {
- try {
- closeResultSet(rs);
- } finally {
- closeStatement(ps);
- }
- }
- }
- /**
- * Long form of the method to execute a query
- *
- * @param request - the request scope
- * @param conn - the database connection
- * @param sql - the SQL statement to execute
- * @param parameters - the parameters for the statement
- * @param skipResults - the number of results to skip
- * @param maxResults - the maximum number of results to return
- * @param callback - the row handler for the query
- *
- * @throws SQLException - if the query fails
- */
- public void executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters,
- int skipResults, int maxResults, RowHandlerCallback callback)
- throws SQLException {
- ErrorContext errorContext = request.getErrorContext();
- errorContext.setActivity("executing query");
- errorContext.setObjectId(sql);
- PreparedStatement ps = null;
- ResultSet rs = null;
- try {
- errorContext.setMoreInfo("Check the SQL Statement (preparation failed).");
- Integer rsType = request.getStatement().getResultSetType();
- if (rsType != null) {
- ps = conn.prepareStatement(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY);
- } else {
- ps = conn.prepareStatement(sql);
- }
- Integer fetchSize = request.getStatement().getFetchSize();
- if (fetchSize != null) {
- ps.setFetchSize(fetchSize.intValue());
- }
- errorContext.setMoreInfo("Check the parameters (set parameters failed).");
- request.getParameterMap().setParameters(request, ps, parameters);
- errorContext.setMoreInfo("Check the statement (query failed).");
- ps.execute();
- rs = getFirstResultSet(ps);
- if (rs != null) {
- errorContext.setMoreInfo("Check the results (failed to retrieve results).");
- handleResults(request, rs, skipResults, maxResults, callback);
- }
- // clear out remaining results
- while (ps.getMoreResults());
- } finally {
- try {
- closeResultSet(rs);
- } finally {
- closeStatement(ps);
- }
- }
- }
/** * Long form of the method to execute a query * * @param request - the request scope * @param conn - the database connection * @param sql - the SQL statement to execute * @param parameters - the parameters for the statement * @param skipResults - the number of results to skip * @param maxResults - the maximum number of results to return * @param callback - the row handler for the query * * @throws SQLException - if the query fails */ public void executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { ErrorContext errorContext = request.getErrorContext(); errorContext.setActivity("executing query"); errorContext.setObjectId(sql); PreparedStatement ps = null; ResultSet rs = null; try { errorContext.setMoreInfo("Check the SQL Statement (preparation failed)."); Integer rsType = request.getStatement().getResultSetType(); if (rsType != null) { ps = conn.prepareStatement(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY); } else { ps = conn.prepareStatement(sql); } Integer fetchSize = request.getStatement().getFetchSize(); if (fetchSize != null) { ps.setFetchSize(fetchSize.intValue()); } errorContext.setMoreInfo("Check the parameters (set parameters failed)."); request.getParameterMap().setParameters(request, ps, parameters); errorContext.setMoreInfo("Check the statement (query failed)."); ps.execute(); rs = getFirstResultSet(ps); if (rs != null) { errorContext.setMoreInfo("Check the results (failed to retrieve results)."); handleResults(request, rs, skipResults, maxResults, callback); } // clear out remaining results while (ps.getMoreResults()); } finally { try { closeResultSet(rs); } finally { closeStatement(ps); } } }
其中handleResults(request, rs, skipResults, maxResults, callback)一句用于处理分页 ,其实此时查询已经执行完毕,可以不必关心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()) {
- break ;
- }
- }
- }
- // 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 );
- }
- }
- 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()) {
- break;
- }
- }
- }
- // 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);
- }
- }
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()) { break; } } } // 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); } }
此处优先使用的是ResultSet的absolute方法定位记录,是否支持absolute取决于具体数据库驱动,但一般当前版本的数据库都支持该方法,如果不支持则逐条跳过前面的记录。由此可以看出如果数据库支持absolute,则ibatis 内置的分页 策略与特定数据库的物理分页 效率差距就在于物理分页 查询与不分页 查询在数据库中的执行效率的差距了。因为查询执行后读取数据前数据库并未把结果全部返回到内存,所以本身在存储占用上应该差距不大,如果都使用索引,估计执行速度也差不太多。
继续我们的话题。其实只要在executeQuery执行前组装sql,然后将其传给 executeQuery,并告诉handleResults我们不需要逻辑分页 即可。拦截executeQuery可以采用aop动态实现,也可直接继承SqlExecutor覆盖executeQuery来静态地实现,相比之下后者要简单许多,而且由于SqlExecutor没有实现任何接口,比较易变,动态拦截反到增加了维护的工作量,所以我们下面来覆盖 executeQuery:
- package com.aladdin.dao.ibatis .ext;
- import java.sql.Connection;
- import java.sql.SQLException;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import com.aladdin.dao.dialect.Dialect;
- import com.ibatis .sqlmap.engine.execution.SqlExecutor;
- import com.ibatis .sqlmap.engine.mapping.statement.RowHandlerCallback;
- import com.ibatis .sqlmap.engine.scope.RequestScope;
- public class LimitSqlExecutor extends SqlExecutor {
- private static final Log logger = LogFactory.getLog(LimitSqlExecutor. class );
- private Dialect dialect;
- private boolean enableLimit = true ;
- public Dialect getDialect() {
- return dialect;
- }
- public void setDialect(Dialect dialect) {
- this .dialect = dialect;
- }
- public boolean isEnableLimit() {
- return enableLimit;
- }
- public void setEnableLimit( boolean enableLimit) {
- this .enableLimit = enableLimit;
- }
- @Override
- public void executeQuery(RequestScope request, Connection conn, String sql,
- Object[] parameters, int skipResults, int maxResults,
- RowHandlerCallback callback) throws SQLException {
- if ((skipResults != NO_SKIPPED_RESULTS || maxResults != NO_MAXIMUM_RESULTS)
- && supportsLimit()) {
- sql = dialect.getLimitString(sql, skipResults, maxResults);
- if (logger.isDebugEnabled()){
- logger.debug(sql);
- }
- skipResults = NO_SKIPPED_RESULTS;
- maxResults = NO_MAXIMUM_RESULTS;
- }
- super .executeQuery(request, conn, sql, parameters, skipResults,
- maxResults, callback);
- }
- public boolean supportsLimit() {
- if (enableLimit && dialect != null ) {
- return dialect.supportsLimit();
- }
- return false ;
- }
- }
- package com.aladdin.dao.<SPAN class=hilite1>ibatis</SPAN>
- .ext;
- import java.sql.Connection;
- import java.sql.SQLException;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import com.aladdin.dao.dialect.Dialect;
- import com.<SPAN class=hilite1>ibatis</SPAN>
- .sqlmap.engine.execution.SqlExecutor;
- import com.<SPAN class=hilite1>ibatis</SPAN>
- .sqlmap.engine.mapping.statement.RowHandlerCallback;
- import com.<SPAN class=hilite1>ibatis</SPAN>
- .sqlmap.engine.scope.RequestScope;
- public class LimitSqlExecutor extends SqlExecutor {
- private static final Log logger = LogFactory.getLog(LimitSqlExecutor.class);
- private Dialect dialect;
- private boolean enableLimit = true;
- public Dialect getDialect() {
- return dialect;
- }
- public void setDialect(Dialect dialect) {
- this.dialect = dialect;
- }
- public boolean isEnableLimit() {
- return enableLimit;
- }
- public void setEnableLimit(boolean enableLimit) {
- this.enableLimit = enableLimit;
- }
- @Override
- public void executeQuery(RequestScope request, Connection conn, String sql,
- Object[] parameters, int skipResults, int maxResults,
- RowHandlerCallback callback) throws SQLException {
- if ((skipResults != NO_SKIPPED_RESULTS || maxResults != NO_MAXIMUM_RESULTS)
- && supportsLimit()) {
- sql = dialect.getLimitString(sql, skipResults, maxResults);
- if(logger.isDebugEnabled()){
- logger.debug(sql);
- }
- skipResults = NO_SKIPPED_RESULTS;
- maxResults = NO_MAXIMUM_RESULTS;
- }
- super.executeQuery(request, conn, sql, parameters, skipResults,
- maxResults, callback);
- }
- public boolean supportsLimit() {
- if (enableLimit && dialect != null) {
- return dialect.supportsLimit();
- }
- return false;
- }
- }
package com.aladdin.dao.ibatis .ext; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.aladdin.dao.dialect.Dialect; import com.ibatis .sqlmap.engine.execution.SqlExecutor; import com.ibatis .sqlmap.engine.mapping.statement.RowHandlerCallback; import com.ibatis .sqlmap.engine.scope.RequestScope; public class LimitSqlExecutor extends SqlExecutor { private static final Log logger = LogFactory.getLog(LimitSqlExecutor.class); private Dialect dialect; private boolean enableLimit = true; public Dialect getDialect() { return dialect; } public void setDialect(Dialect dialect) { this.dialect = dialect; } public boolean isEnableLimit() { return enableLimit; } public void setEnableLimit(boolean enableLimit) { this.enableLimit = enableLimit; } @Override public void executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException { if ((skipResults != NO_SKIPPED_RESULTS || maxResults != NO_MAXIMUM_RESULTS) && supportsLimit()) { sql = dialect.getLimitString(sql, skipResults, maxResults); if(logger.isDebugEnabled()){ logger.debug(sql); } skipResults = NO_SKIPPED_RESULTS; maxResults = NO_MAXIMUM_RESULTS; } super.executeQuery(request, conn, sql, parameters, skipResults, maxResults, callback); } public boolean supportsLimit() { if (enableLimit && dialect != null) { return dialect.supportsLimit(); } return false; } }
其中:
skipResults = NO_SKIPPED_RESULTS; maxResults = NO_MAXIMUM_RESULTS;
告诉handleResults不分页 (我们组装的sql已经使查询结果是分页 后的结果了),此处引入了类似hibenate中的数据库方言 接口Dialect,其代码如下:
- package com.aladdin.dao.dialect;
- public interface Dialect {
- public boolean supportsLimit();
- public String getLimitString(String sql, boolean hasOffset);
- public String getLimitString(String sql, int offset, int limit);
- }
- package com.aladdin.dao.dialect;
- public interface Dialect {
- public boolean supportsLimit();
- public String getLimitString(String sql, boolean hasOffset);
- public String getLimitString(String sql, int offset, int limit);
- }
package com.aladdin.dao.dialect; public interface Dialect { public boolean supportsLimit(); public String getLimitString(String sql, boolean hasOffset); public String getLimitString(String sql, int offset, int limit); }
下面为Dialect接口的MySQL实现:
- package com.aladdin.dao.dialect;
- public class MySQLDialect implements Dialect {
- protected static final String SQL_END_DELIMITER = ";" ;
- public String getLimitString(String sql, boolean hasOffset) {
- return new StringBuffer(sql.length() + 20 ).append(trim(sql)).append(
- hasOffset ? " limit ?,?" : " limit ?" )
- .append(SQL_END_DELIMITER).toString();
- }
- public String getLimitString(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)
- .append(SQL_END_DELIMITER);
- } else {
- sb.append(" limit " ).append(limit).append(SQL_END_DELIMITER);
- }
- return sb.toString();
- }
- public boolean supportsLimit() {
- return true ;
- }
- private 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;
- }
- }
- package com.aladdin.dao.dialect;
- public class MySQLDialect implements Dialect {
- protected static final String SQL_END_DELIMITER = ";";
- public String getLimitString(String sql, boolean hasOffset) {
- return new StringBuffer(sql.length() + 20).append(trim(sql)).append(
- hasOffset ? " limit ?,?" : " limit ?")
- .append(SQL_END_DELIMITER).toString();
- }
- public String getLimitString(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)
- .append(SQL_END_DELIMITER);
- } else {
- sb.append(" limit ").append(limit).append(SQL_END_DELIMITER);
- }
- return sb.toString();
- }
- public boolean supportsLimit() {
- return true;
- }
- private 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;
- }
- }
package com.aladdin.dao.dialect; public class MySQLDialect implements Dialect { protected static final String SQL_END_DELIMITER = ";"; public String getLimitString(String sql, boolean hasOffset) { return new StringBuffer(sql.length() + 20).append(trim(sql)).append( hasOffset ? " limit ?,?" : " limit ?") .append(SQL_END_DELIMITER).toString(); } public String getLimitString(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) .append(SQL_END_DELIMITER); } else { sb.append(" limit ").append(limit).append(SQL_END_DELIMITER); } return sb.toString(); } public boolean supportsLimit() { return true; } private 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; } }
接下来的工作就是把LimitSqlExecutor注入ibatis 中。我们是通过spring来使用ibatis 的,所以在我们的dao基类中执行注入,代码如下:
- package com.aladdin.dao.ibatis ;
- import java.io.Serializable;
- import java.util.List;
- import org.springframework.orm.ObjectRetrievalFailureException;
- import org.springframework.orm.ibatis .support.SqlMapClientDaoSupport;
- import com.aladdin.dao.ibatis .ext.LimitSqlExecutor;
- import com.aladdin.domain.BaseObject;
- import com.aladdin.util.ReflectUtil;
- import com.ibatis .sqlmap.client.SqlMapClient;
- import com.ibatis .sqlmap.engine.execution.SqlExecutor;
- import com.ibatis .sqlmap.engine.impl.ExtendedSqlMapClient;
- public abstract class BaseDaoiBatis extends SqlMapClientDaoSupport {
- private SqlExecutor sqlExecutor;
- public SqlExecutor getSqlExecutor() {
- return sqlExecutor;
- }
- public void setSqlExecutor(SqlExecutor sqlExecutor) {
- this .sqlExecutor = sqlExecutor;
- }
- public void setEnableLimit( boolean enableLimit) {
- if (sqlExecutor instanceof LimitSqlExecutor) {
- ((LimitSqlExecutor) sqlExecutor).setEnableLimit(enableLimit);
- }
- }
- public void initialize() throws Exception {
- if (sqlExecutor != null ) {
- SqlMapClient sqlMapClient = getSqlMapClientTemplate()
- .getSqlMapClient();
- if (sqlMapClient instanceof ExtendedSqlMapClient) {
- ReflectUtil.setFieldValue(((ExtendedSqlMapClient) sqlMapClient)
- .getDelegate(), "sqlExecutor" , SqlExecutor. class ,
- sqlExecutor);
- }
- }
- }
- ...
- }
- package com.aladdin.dao.<SPAN class=hilite1>ibatis</SPAN>
- ;
- import java.io.Serializable;
- import java.util.List;
- import org.springframework.orm.ObjectRetrievalFailureException;
- import org.springframework.orm.<SPAN class=hilite1>ibatis</SPAN>
- .support.SqlMapClientDaoSupport;
- import com.aladdin.dao.<SPAN class=hilite1>ibatis</SPAN>
- .ext.LimitSqlExecutor;
- import com.aladdin.domain.BaseObject;
- import com.aladdin.util.ReflectUtil;
- import com.<SPAN class=hilite1>ibatis</SPAN>
- .sqlmap.client.SqlMapClient;
- import com.<SPAN class=hilite1>ibatis</SPAN>
- .sqlmap.engine.execution.SqlExecutor;
- import com.<SPAN class=hilite1>ibatis</SPAN>
- .sqlmap.engine.impl.ExtendedSqlMapClient;
- public abstract class BaseDao<SPAN class=hilite1>iBatis</SPAN>
- extends SqlMapClientDaoSupport {
- private SqlExecutor sqlExecutor;
- public SqlExecutor getSqlExecutor() {
- return sqlExecutor;
- }
- public void setSqlExecutor(SqlExecutor sqlExecutor) {
- this.sqlExecutor = sqlExecutor;
- }
- public void setEnableLimit(boolean enableLimit) {
- if (sqlExecutor instanceof LimitSqlExecutor) {
- ((LimitSqlExecutor) sqlExecutor).setEnableLimit(enableLimit);
- }
- }
- public void initialize() throws Exception {
- if (sqlExecutor != null) {
- SqlMapClient sqlMapClient = getSqlMapClientTemplate()
- .getSqlMapClient();
- if (sqlMapClient instanceof ExtendedSqlMapClient) {
- ReflectUtil.setFieldValue(((ExtendedSqlMapClient) sqlMapClient)
- .getDelegate(), "sqlExecutor", SqlExecutor.class,
- sqlExecutor);
- }
- }
- }
- ...
- }
package com.aladdin.dao.ibatis ; import java.io.Serializable; import java.util.List; import org.springframework.orm.ObjectRetrievalFailureException; import org.springframework.orm.ibatis .support.SqlMapClientDaoSupport; import com.aladdin.dao.ibatis .ext.LimitSqlExecutor; import com.aladdin.domain.BaseObject; import com.aladdin.util.ReflectUtil; import com.ibatis .sqlmap.client.SqlMapClient; import com.ibatis .sqlmap.engine.execution.SqlExecutor; import com.ibatis .sqlmap.engine.impl.ExtendedSqlMapClient; public abstract class BaseDaoiBatis extends SqlMapClientDaoSupport { private SqlExecutor sqlExecutor; public SqlExecutor getSqlExecutor() { return sqlExecutor; } public void setSqlExecutor(SqlExecutor sqlExecutor) { this.sqlExecutor = sqlExecutor; } public void setEnableLimit(boolean enableLimit) { if (sqlExecutor instanceof LimitSqlExecutor) { ((LimitSqlExecutor) sqlExecutor).setEnableLimit(enableLimit); } } public void initialize() throws Exception { if (sqlExecutor != null) { SqlMapClient sqlMapClient = getSqlMapClientTemplate() .getSqlMapClient(); if (sqlMapClient instanceof ExtendedSqlMapClient) { ReflectUtil.setFieldValue(((ExtendedSqlMapClient) sqlMapClient) .getDelegate(), "sqlExecutor", SqlExecutor.class, sqlExecutor); } } } ... }
其中的initialize方法执行注入,稍后会看到此方法在spring Beans 配置中指定为init-method。由于sqlExecutor是 com.ibatis .sqlmap.engine.impl.ExtendedSqlMapClient的私有成员,且没有公开的set方法,所以此处通过反射绕过java的访问控制,下面是ReflectUtil的实现代码:
- package com.aladdin.util;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.lang.reflect.Modifier;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- public class ReflectUtil {
- private static final Log logger = LogFactory.getLog(ReflectUtil. class );
- public static void setFieldValue(Object target, String fname, Class ftype,
- Object fvalue) {
- if (target == null
- || fname == null
- || "" .equals(fname)
- || (fvalue != null && !ftype.isAssignableFrom(fvalue.getClass()))) {
- return ;
- }
- Class clazz = target.getClass();
- try {
- Method method = clazz.getDeclaredMethod("set"
- + Character.toUpperCase(fname.charAt(0 ))
- + fname.substring(1 ), ftype);
- if (!Modifier.isPublic(method.getModifiers())) {
- method.setAccessible(true );
- }
- method.invoke(target, fvalue);
- } catch (Exception me) {
- if (logger.isDebugEnabled()) {
- logger.debug(me);
- }
- try {
- Field field = clazz.getDeclaredField(fname);
- if (!Modifier.isPublic(field.getModifiers())) {
- field.setAccessible(true );
- }
- field.set(target, fvalue);
- } catch (Exception fe) {
- if (logger.isDebugEnabled()) {
- logger.debug(fe);
- }
- }
- }
- }
- }
- package com.aladdin.util;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.lang.reflect.Modifier;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- public class ReflectUtil {
- private static final Log logger = LogFactory.getLog(ReflectUtil.class);
- public static void setFieldValue(Object target, String fname, Class ftype,
- Object fvalue) {
- if (target == null
- || fname == null
- || "".equals(fname)
- || (fvalue != null && !ftype.isAssignableFrom(fvalue.getClass()))) {
- return;
- }
- Class clazz = target.getClass();
- try {
- Method method = clazz.getDeclaredMethod("set"
- + Character.toUpperCase(fname.charAt(0))
- + fname.substring(1), ftype);
- if (!Modifier.isPublic(method.getModifiers())) {
- method.setAccessible(true);
- }
- method.invoke(target, fvalue);
- } catch (Exception me) {
- if (logger.isDebugEnabled()) {
- logger.debug(me);
- }
- try {
- Field field = clazz.getDeclaredField(fname);
- if (!Modifier.isPublic(field.getModifiers())) {
- field.setAccessible(true);
- }
- field.set(target, fvalue);
- } catch (Exception fe) {
- if (logger.isDebugEnabled()) {
- logger.debug(fe);
- }
- }
- }
- }
- }
package com.aladdin.util; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class ReflectUtil { private static final Log logger = LogFactory.getLog(ReflectUtil.class); public static void setFieldValue(Object target, String fname, Class ftype, Object fvalue) { if (target == null || fname == null || "".equals(fname) || (fvalue != null && !ftype.isAssignableFrom(fvalue.getClass()))) { return; } Class clazz = target.getClass(); try { Method method = clazz.getDeclaredMethod("set" + Character.toUpperCase(fname.charAt(0)) + fname.substring(1), ftype); if (!Modifier.isPublic(method.getModifiers())) { method.setAccessible(true); } method.invoke(target, fvalue); } catch (Exception me) { if (logger.isDebugEnabled()) { logger.debug(me); } try { Field field = clazz.getDeclaredField(fname); if (!Modifier.isPublic(field.getModifiers())) { field.setAccessible(true); } field.set(target, fvalue); } catch (Exception fe) { if (logger.isDebugEnabled()) { logger.debug(fe); } } } } }
到此剩下的就是通过Spring将sqlExecutor注入BaseDaoiBatis 中了,下面是Spring Beans配置文件:
- <? xml version = "1.0" encoding = "UTF-8" ?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
- "http://www.springframework.org/dtd/spring-beans.dtd">
- < beans >
- <!-- Transaction manager for a single JDBC DataSource -->
- < bean id = "transactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
- < property name = "dataSource" >
- < ref bean = "dataSource" />
- </ property >
- </ bean >
- <!-- SqlMap setup for iBATIS Database Layer -->
- < bean id = "sqlMapClient" class = "org.springf
发表评论
-
安装和使用memcached
2014-04-16 16:24 641如何将 memcached 融入到 ... -
applicationContext.xml
2013-08-09 09:05 941<?xml version="1.0&quo ... -
注释驱动的 Spring cache 缓存介绍
2013-08-08 07:04 659概述 Spring 3.1 引入了激动人心的基于注释(an ... -
Spring2.5 Annotations
2013-08-08 06:33 854完成setXxxx功能,即配置文件的 <propert ... -
Spring基于注解的缓存配置--EHCache AND OSCache
2013-08-07 23:21 1026本文将构建一个普通工程来说明spring注解缓存的使用方式, ... -
Ehcache 整合Spring 使用页面、对象缓存
2013-08-07 22:51 893Ehcache 整合Spring 使用页面、对象缓存 ... -
javassist教程和示例
2013-05-18 08:57 2008Javassist是一个执行字节 ... -
ZooKeeper官方文档
2013-05-16 17:09 1559介绍(源自ZooKeeper官方文档) 学习HBase过程 ... -
ZooKeeper -例子
2013-05-16 17:08 1206ZooKeeper ZooKeepe ... -
Spring整合Hessian访问远程服务
2013-05-15 13:44 853Spring整合Hessian访问远程服务 目录 1.1 ... -
redis
2013-05-14 11:44 767redis是一个key-value存储系统。和Memcach ... -
spring 资源访问
2013-05-13 08:26 996spring在java基础上封装了资源访问,简单易用。 R ... -
ZooKeeper——入门
2013-05-08 16:12 909ZooKeeper——入门 博客分类: ZooK ... -
分布式服务框架 Zookeeper -- 管理分布式环境中的数据(IBM)
2013-05-08 14:07 784安装和配置详解 本文 ... -
分布式协调服务---Zookeeper
2013-05-08 14:05 7741、Zookeeper overview Zookee ... -
Hibernate
2013-03-28 13:04 923一、简述 Hibernate 和 JD ... -
Apache+Tomcat集群配置详解
2013-02-01 10:52 890Apache + Tomcat集群配置详解(1) 一、 ... -
Apache+Jboss集群基于反向代理的负载均衡
2013-02-01 10:40 2490假设三台机器IP分别为172.29.128.100、172. ... -
spring + ibatis 多数据源事务(分布式事务)管理配置方法
2012-12-17 15:18 1265spring + ibatis 多数据源事务(分布式事务 ... -
Hessian序列化不设SerializerFactory性能问题
2012-10-31 09:47 1492Hessian序列化不设SerializerFactor ...
相关推荐
标题中的“ibatis分页”指的是在使用iBATIS(一个SQL映射框架)时,如何实现数据库查询结果的分页显示。iBATIS通过XML配置文件或注解方式将Java代码与SQL语句分离,提供了更灵活的数据库操作方式。在处理大量数据时...
标题"ibatis分页功能"指的就是如何在iBATIS框架中实现数据库查询的分页效果。分页不仅提高了用户体验,还能减少不必要的数据库负载。 描述中提到,分页功能是通过`page.tld`标签实现的。`tld`文件是JSP Tag Library...
本文将深入探讨Ibatis实现分页的相关知识点,并基于提供的标签“源码”和“工具”,分享如何在实际项目中运用Ibatis进行分页处理。 首先,了解Ibatis的基本概念。Ibatis是由Apache基金会维护的一个开源项目,它是一...
iBatis分页源代码解析.chm,ibatis介绍等
本知识点将深入探讨如何在Struts2框架中结合iBatis实现基于Freemarker模板的分页功能。 首先,我们需要理解iBatis,它是一个轻量级的Java持久层框架,它提供了一个SQL映射框架,允许开发者将SQL语句与Java代码分离...
公司的大部分项目都开始使用IBatis作为O/R Mapping了,但是在使用的过程中也发现了很多不方便和存在争议的地方,其中一个不方便的地方就是分页,目前的处理方式都是在sqlMap中写针对特定数据库的物理分页Sql语句,对于...
### ibatis分页技术详解与应用 在软件开发领域,特别是在数据库操作中,分页是一项极为常见的需求。分页不仅可以优化用户体验,减少加载时间,还能有效地管理大量的数据查询结果。Ibatis,作为一款优秀的持久层框架...
本篇文章将深入探讨如何在Xwork和iBatis的集成应用中实现分页功能,让开发者能够更高效地处理大量数据。 首先,让我们了解什么是分页。分页是网页显示大量数据时常用的一种技术,它将结果集分割成若干小部分(页)...
在传统的iBatis框架中,分页通常采用逻辑分页的方式,即通过游标(ResultSet)来逐条处理数据,从而实现分页效果。这种方式虽然跨数据库兼容性好,但性能上不如数据库原生的物理分页高效。物理分页是直接在SQL语句中...
三、Ibatis分页实现 1. SQL配置 在Ibatis的Mapper XML文件中,我们需要编写一个带有参数的SQL查询,这些参数通常包括当前页码和每页记录数。例如: ```xml SELECT * FROM your_table != null and pageSize != ...
本项目基于ibatis框架实现了分页功能,覆盖了从底层数据库操作到页面展示的完整流程,包括DAO层、Service层、Action层以及JSP页面的展示。 首先,我们来了解一下什么是ibatis。Ibatis是一个优秀的持久层框架,它...
ibatis_likehbm高效分页组件ibatis_likehbm高效分页组件ibatis_likehbm高效分页组件ibatis_likehbm高效分页组件ibatis_likehbm高效分页组件ibatis_likehbm高效分页组件 ibatis_likehbm高效分页组件 ibatis_likehbm...
在2.3.4这个版本中,Ibatis 提供了数据库无关的分页功能,这是一种在不依赖特定数据库语法的情况下实现分页查询的方法,有助于提高代码的可移植性和维护性。 数据库无关分页的核心思想是将分页参数(如当前页数和每...
NULL 博文链接:https://jsufly.iteye.com/blog/508249
你可以定义一个Mapper接口和XML配置文件,编写SQL查询来获取指定页码的数据,并通过iBatis的参数映射功能传入分页参数。 文件列表中的`.classpath`和`.project`是Eclipse或类似的IDE的项目配置文件,它们定义了项目...
本项目"ibatis_with_memcached"就是关于如何将Ibatis与Memcached集成,实现高效的数据库缓存策略的实例。 Ibatis是一个基于Java的SQL映射框架,它允许开发者编写SQL语句并与Java对象进行绑定,从而避免了传统的JDBC...
ibatis 物理分页jar ,与官方ibatis不冲突,可直接使用。
"iBatis分页"是数据库操作中常见的需求,iBatis提供了方便的分页支持。在学习这部分时,你会了解如何在SQL中添加分页条件,以及如何在Java代码中处理分页结果。 "spring+iBatis处理1对多数据表实例"展示了如何将...
Ibatis.NET提供了分页查询的实现,下面我们将深入探讨如何在Ibatis.NET中实现分页。 首先,理解分页的基本概念。分页通常涉及两个关键参数:当前页码(Page Number)和每页记录数(PageSize)。例如,如果当前页码...
Ibatis SQLServerDialect 2008 分页 可实现SQLServerDialect 分页 支持ibatis3