欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
使ibatis支持hibernate式的物理分頁(yè)

一直以來(lái)ibatis的分頁(yè)都是通過(guò)滾動(dòng)ResultSet實(shí)現的,應該算是邏輯分頁(yè)吧。邏輯分頁(yè)雖然能很干凈地獨立于特定數據庫,但效率在多數情況下不及特定數據庫支持的物理分頁(yè),而hibernate的分頁(yè)則是直接組裝sql,充分利用了特定數據庫的分頁(yè)機制,效率相對較高。本文講述的就是如何在不重新編譯ibatis源碼的前提下,為ibatis引入hibernate式的物理分頁(yè)機制。

基本思路就是找到ibatis執行sql的地方,截獲sql并重新組裝sql。通過(guò)分析ibatis源碼知道,最終負責執行sql的類(lèi)是com.ibatis.sqlmap.engine.execution.SqlExecutor,此類(lèi)沒(méi)有實(shí)現任何接口,這多少有點(diǎn)遺憾,因為接口是相對穩定契約,非大的版本更新,接口一般是不會(huì )變的,而類(lèi)就相對易變一些,所以這里的代碼只能保證對當前版本(2.1.7)的ibatis有效。下面是SqlExecutor執行查詢(xún)的方法:

  /**
   * 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)一句用于處理分頁(yè),其實(shí)此時(shí)查詢(xún)已經(jīng)執行完畢,可以不必關(guān)心handleResults方法,但為清楚起見(jiàn),下面來(lái)看看handleResults的實(shí)現:

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);
    }
  }

 

此處優(yōu)先使用的是ResultSet的absolute方法定位記錄,是否支持absolute取決于具體數據庫驅動(dòng),但一般當前版本的數據庫都支持該方法,如果不支持則逐條跳過(guò)前面的記錄。由此可以看出如果數據庫支持absolute,則ibatis內置的分頁(yè)策略與特定數據庫的物理分頁(yè)效率差距就在于物理分頁(yè)查詢(xún)與不分頁(yè)查詢(xún)在數據庫中的執行效率的差距了。因為查詢(xún)執行后讀取數據前數據庫并未把結果全部返回到內存,所以本身在存儲占用上應該差距不大,如果都使用索引,估計執行速度也差不太多。

繼續我們的話(huà)題。其實(shí)只要在executeQuery執行前組裝sql,然后將其傳給executeQuery,并告訴handleResults我們不需要邏輯分頁(yè)即可。攔截executeQuery可以采用aop動(dòng)態(tài)實(shí)現,也可直接繼承SqlExecutor覆蓋executeQuery來(lái)靜態(tài)地實(shí)現,相比之下后者要簡(jiǎn)單許多,而且由于SqlExecutor沒(méi)有實(shí)現任何接口,比較易變,動(dòng)態(tài)攔截反到增加了維護的工作量,所以我們下面來(lái)覆蓋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;
    }

}

其中:

skipResults = NO_SKIPPED_RESULTS;
maxResults 
= NO_MAXIMUM_RESULTS;

告訴handleResults不分頁(yè)(我們組裝的sql已經(jīng)使查詢(xún)結果是分頁(yè)后的結果了),此處引入了類(lèi)似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);
}

 

下面為Dialect接口的MySQL實(shí)現: 

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;
    }

}

接下來(lái)的工作就是把LimitSqlExecutor注入ibatis中。我們是通過(guò)spring來(lái)使用ibatis的,所以在我們的dao基類(lèi)中執行注入,代碼如下:

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方法執行注入,稍后會(huì )看到此方法在springBeans 配置中指定為init-method。由于sqlExecutor是com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient的私有成員,且沒(méi)有公開(kāi)的set方法,所以此處通過(guò)反射繞過(guò)java的訪(fǎng)問(wèn)控制,下面是ReflectUtil的實(shí)現代碼:

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);
                }
            }
        }
    }
}

 

到此剩下的就是通過(guò)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.springframework.orm.ibatis.SqlMapClientFactoryBean">
        
<property name="configLocation">
            
<value>classpath:/com/aladdin/dao/ibatis/sql-map-config.xml</value>
        
</property>
        
<property name="dataSource">
            
<ref bean="dataSource" />
        
</property>
    
</bean>

    
<bean id="sqlExecutor" class="com.aladdin.dao.ibatis.ext.LimitSqlExecutor">
        
<property name="dialect">
            
<bean class="com.aladdin.dao.dialect.MySQLDialect" />
        
</property>
    
</bean>
    
    
<bean id="baseDao" abstract="true" class="com.aladdin.dao.ibatis.BaseDaoiBatis" init-method="initialize">
        
<property name="dataSource">
            
<ref bean="dataSource" />
        
</property>
        
<property name="sqlMapClient">
            
<ref bean="sqlMapClient" />
        
</property>
        
<property name="sqlExecutor">
            
<ref bean="sqlExecutor" />
        
</property> 
    
</bean> 
    
    
<bean id="userDao" class="com.aladdin.dao.ibatis.UserDaoiBatis" parent="baseDao" /> 

    
<bean id="roleDao" class="com.aladdin.dao.ibatis.RoleDaoiBatis" parent="baseDao" />
    
    
<bean id="resourceDao" class="com.aladdin.dao.ibatis.ResourceDaoiBatis" parent="baseDao" />
    
</beans>

 

此后就可以通過(guò)調用org.springframework.orm.ibatis.SqlMapClientTemplate的

publicList queryForList(final String statementName, final ObjectparameterObject, final int skipResults, final int maxResults)   throwsDataAccessException

public PaginatedListqueryForPaginatedList(final String statementName, final ObjectparameterObject, final int pageSize)   throws DataAccessException

得到分頁(yè)結果了。建議使用第一個(gè)方法,第二個(gè)方法返回的是PaginatedList,雖然使用簡(jiǎn)單,但是其獲得指定頁(yè)的數據是跨過(guò)我們的dao直接訪(fǎng)問(wèn)ibatis的,不方便統一管理。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
ibatis中queryForPaginatedList分頁(yè) 源碼分析
iBATIS,循序漸進(jìn)介紹如何做O/R Mapping
mybatis下的分頁(yè),支持所有的數據庫
mybatis實(shí)戰教程(mybatis in action)之七:實(shí)現mybatis分頁(yè)(源碼下載)
Mybatis使用之分頁(yè)
iBatis2-SqlMap的配置總結
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久