对IBatis分页的改进,使ibatis支持hibernate式的物理分页--转载

关键字: ibatis spring 分页 物理分页

      公司的大部分项目都开始使用IBatis作为O/R Mapping了,但是在使用的过程中也发现了很多不方便和存在争议的地方,其中一个不方便的地方就是分页,目前的处理方式都是在sqlMap中写针对特 定数据库的物理分页Sql语句,对于oracle数据库都是在分页的sql语句里面加上三层嵌套的sql语句,想了很多办法,都没能很好的避免这个问题, 无意间在javaeye上看到了《使ibatis支持hibernate式的物理分页》这篇文章,可点进去已经被删除了 ,幸好google了一下有很多人已经收藏了,这里转载一下 ,以便再找不到了.

 

转载地址:http://www.blogjava.net/libin2722/articles/192504.html

 

一 直以来ibatis的分页都是通过滚动ResultSet实现的,应该算是逻辑分页吧。逻辑分页虽然能很干净地独立于特定数据库,但效率在多数情况下不及 特定数据库支持的物理分页,而hibernate的分页则是直接组装sql,充分利用了特定数据库的分页机制,效率相对较高。本文讲述的就是如何在不重新 编译ibatis源码的前提下,为ibatis引入hibernate式的物理分页机制。

基本思路就是找到ibatis执行sql的地 方,截获sql并重新组装sql。通过分析ibatis源码知道,最终负责执行sql的类是 com.ibatis.sqlmap.engine.execution.SqlExecutor,此类没有实现任何接口,这多少有点遗憾,因为接口是相 对稳定契约,非大的版本更新,接口一般是不会变的,而类就相对易变一些,所以这里的代码只能保证对当前版本(2.1.7)的ibatis有效。下面是 SqlExecutor执行查询的方法:

Java代码 复制代码
  1. /**  
  2.    * Long form of the method to execute a query  
  3.    *  
  4.    * @param request - the request scope  
  5.    * @param conn - the database connection  
  6.    * @param sql - the SQL statement to execute  
  7.    * @param parameters - the parameters for the statement  
  8.    * @param skipResults - the number of results to skip  
  9.    * @param maxResults - the maximum number of results to return  
  10.    * @param callback - the row handler for the query  
  11.    *  
  12.    * @throws SQLException - if the query fails  
  13.    */   
  14.    public   void  executeQuery(RequestScope request, Connection conn, String sql, Object[] parameters,   
  15.                             int  skipResults,  int  maxResults, RowHandlerCallback callback)   
  16.        throws  SQLException {   
  17.     ErrorContext errorContext = request.getErrorContext();   
  18.     errorContext.setActivity( "executing query" );   
  19.     errorContext.setObjectId(sql);   
  20.   
  21.     PreparedStatement ps =  null ;   
  22.     ResultSet rs =  null ;   
  23.   
  24.      try  {   
  25.       errorContext.setMoreInfo( "Check the SQL Statement (preparation failed)." );   
  26.   
  27.       Integer rsType = request.getStatement().getResultSetType();   
  28.        if  (rsType !=  null ) {   
  29.         ps = conn.prepareStatement(sql, rsType.intValue(), ResultSet.CONCUR_READ_ONLY);   
  30.       }  else  {   
  31.         ps = conn.prepareStatement(sql);   
  32.       }   
  33.   
  34.       Integer fetchSize = request.getStatement().getFetchSize();   
  35.        if  (fetchSize !=  null ) {   
  36.         ps.setFetchSize(fetchSize.intValue());   
  37.       }   
  38.   
  39.       errorContext.setMoreInfo( "Check the parameters (set parameters failed)." );   
  40.       request.getParameterMap().setParameters(request, ps, parameters);   
  41.   
  42.       errorContext.setMoreInfo( "Check the statement (query failed)." );   
  43.   
  44.       ps.execute();   
  45.       rs = getFirstResultSet(ps);   
  46.   
  47.        if  (rs !=  null ) {   
  48.         errorContext.setMoreInfo( "Check the results (failed to retrieve results)." );   
  49.         handleResults(request, rs, skipResults, maxResults, callback);   
  50.       }   
  51.   
  52.        // clear out remaining results   
  53.        while  (ps.getMoreResults());   
  54.   
  55.     }  finally  {   
  56.        try  {   
  57.         closeResultSet(rs);   
  58.       }  finally  {   
  59.         closeStatement(ps);   
  60.       }   
  61.     }   
  62.   
  63.   }  
/** * 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的实现:

Java代码 复制代码
  1. private   void  handleResults(RequestScope request, ResultSet rs,  int  skipResults,  int  maxResults, RowHandlerCallback callback)  throws  SQLException {   
  2.      try  {   
  3.       request.setResultSet(rs);   
  4.       ResultMap resultMap = request.getResultMap();   
  5.        if  (resultMap !=  null ) {   
  6.          // Skip Results   
  7.          if  (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {   
  8.            if  (skipResults >  0 ) {   
  9.             rs.absolute(skipResults);   
  10.           }   
  11.         }  else  {   
  12.            for  ( int  i =  0 ; i < skipResults; i++) {   
  13.              if  (!rs.next()) {   
  14.                break ;   
  15.             }   
  16.           }   
  17.         }   
  18.   
  19.          // Get Results   
  20.          int  resultsFetched =  0 ;   
  21.          while  ((maxResults == SqlExecutor.NO_MAXIMUM_RESULTS || resultsFetched < maxResults) && rs.next()) {   
  22.           Object[] columnValues = resultMap.resolveSubMap(request, rs).getResults(request, rs);   
  23.           callback.handleResultObject(request, columnValues, rs);   
  24.           resultsFetched++;   
  25.         }   
  26.       }   
  27.     }  finally  {   
  28.       request.setResultSet( null );   
  29.     }   
  30.   }  
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:

Java代码 复制代码
  1. package  com.aladdin.dao.ibatis.ext;   
  2.   
  3. import  java.sql.Connection;   
  4. import  java.sql.SQLException;   
  5.   
  6. import  org.apache.commons.logging.Log;   
  7. import  org.apache.commons.logging.LogFactory;   
  8.   
  9. import  com.aladdin.dao.dialect.Dialect;   
  10. import  com.ibatis.sqlmap.engine.execution.SqlExecutor;   
  11. import  com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback;   
  12. import  com.ibatis.sqlmap.engine.scope.RequestScope;   
  13.   
  14. public   class  LimitSqlExecutor  extends  SqlExecutor {   
  15.   
  16.      private   static   final  Log logger = LogFactory.getLog(LimitSqlExecutor. class );   
  17.        
  18.      private  Dialect dialect;   
  19.   
  20.      private   boolean  enableLimit =  true ;   
  21.   
  22.      public  Dialect getDialect() {   
  23.          return  dialect;   
  24.     }   
  25.   
  26.      public   void  setDialect(Dialect dialect) {   
  27.          this .dialect = dialect;   
  28.     }   
  29.   
  30.      public   boolean  isEnableLimit() {   
  31.          return  enableLimit;   
  32.     }   
  33.   
  34.      public   void  setEnableLimit( boolean  enableLimit) {   
  35.          this .enableLimit = enableLimit;   
  36.     }   
  37.   
  38.      @Override   
  39.      public   void  executeQuery(RequestScope request, Connection conn, String sql,   
  40.             Object[] parameters,  int  skipResults,  int  maxResults,   
  41.             RowHandlerCallback callback)  throws  SQLException {   
  42.          if  ((skipResults != NO_SKIPPED_RESULTS || maxResults != NO_MAXIMUM_RESULTS)   
  43.                 && supportsLimit()) {   
  44.             sql = dialect.getLimitString(sql, skipResults, maxResults);   
  45.              if (logger.isDebugEnabled()){   
  46.                 logger.debug(sql);   
  47.             }   
  48.             skipResults = NO_SKIPPED_RESULTS;   
  49.             maxResults = NO_MAXIMUM_RESULTS;               
  50.         }   
  51.          super .executeQuery(request, conn, sql, parameters, skipResults,   
  52.                 maxResults, callback);   
  53.     }   
  54.   
  55.      public   boolean  supportsLimit() {   
  56.          if  (enableLimit && dialect !=  null ) {   
  57.              return  dialect.supportsLimit();   
  58.         }   
  59.          return   false ;   
  60.     }   
  61.   
  62. }  
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; } }

 其中:

Java代码 复制代码
  1. skipResults = NO_SKIPPED_RESULTS;   
  2. maxResults = NO_MAXIMUM_RESULTS;  
skipResults = NO_SKIPPED_RESULTS; maxResults = NO_MAXIMUM_RESULTS;

 告诉handleResults不分页(我们组装的sql已经使查询结果是分页后的结果了),此处引入了类似hibenate中的数据库方言接口Dialect,其代码如下:

Java代码 复制代码
  1. package  com.aladdin.dao.dialect;   
  2.   
  3. public   interface  Dialect {   
  4.        
  5.      public   boolean  supportsLimit();   
  6.   
  7.      public  String getLimitString(String sql,  boolean  hasOffset);   
  8.   
  9.      public  String getLimitString(String sql,  int  offset,  int  limit);   
  10. }  
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实现:

Java代码 复制代码
  1. package  com.aladdin.dao.dialect;   
  2.   
  3. public   class  MySQLDialect  implements  Dialect {   
  4.   
  5.      protected   static   final  String SQL_END_DELIMITER =  ";" ;   
  6.   
  7.      public  String getLimitString(String sql,  boolean  hasOffset) {   
  8.          return   new  StringBuffer(sql.length() +  20 ).append(trim(sql)).append(   
  9.                 hasOffset ?  " limit ?,?"  :  " limit ?" )   
  10.                 .append(SQL_END_DELIMITER).toString();   
  11.     }   
  12.   
  13.      public  String getLimitString(String sql,  int  offset,  int  limit) {   
  14.         sql = trim(sql);   
  15.         StringBuffer sb =  new  StringBuffer(sql.length() +  20 );   
  16.         sb.append(sql);   
  17.          if  (offset >  0 ) {   
  18.             sb.append( " limit " ).append(offset).append( ',' ).append(limit)   
  19.                     .append(SQL_END_DELIMITER);   
  20.         }  else  {   
  21.             sb.append( " limit " ).append(limit).append(SQL_END_DELIMITER);   
  22.         }   
  23.          return  sb.toString();   
  24.     }   
  25.   
  26.      public   boolean  supportsLimit() {   
  27.          return   true ;   
  28.     }   
  29.   
  30.      private  String trim(String sql) {   
  31.         sql = sql.trim();   
  32.          if  (sql.endsWith(SQL_END_DELIMITER)) {   
  33.             sql = sql.substring( 0 , sql.length() -  1   
  34.                     - SQL_END_DELIMITER.length());   
  35.         }   
  36.          return  sql;   
  37.     }   
  38.   
  39. }  
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基类中执行注入,代码如下:

Java代码 复制代码
  1. package  com.aladdin.dao.ibatis;   
  2.   
  3. import  java.io.Serializable;   
  4. import  java.util.List;   
  5.   
  6. import  org.springframework.orm.ObjectRetrievalFailureException;   
  7. import  org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;   
  8.   
  9. import  com.aladdin.dao.ibatis.ext.LimitSqlExecutor;   
  10. import  com.aladdin.domain.BaseObject;   
  11. import  com.aladdin.util.ReflectUtil;   
  12. import  com.ibatis.sqlmap.client.SqlMapClient;   
  13. import  com.ibatis.sqlmap.engine.execution.SqlExecutor;   
  14. import  com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;   
  15.   
  16. public   abstract   class  BaseDaoiBatis  extends  SqlMapClientDaoSupport {   
  17.   
  18.      private  SqlExecutor sqlExecutor;   
  19.   
  20.      public  SqlExecutor getSqlExecutor() {   
  21.          return  sqlExecutor;   
  22.     }   
  23.   
  24.      public   void  setSqlExecutor(SqlExecutor sqlExecutor) {   
  25.          this .sqlExecutor = sqlExecutor;   
  26.     }   
  27.   
  28.      public   void  setEnableLimit( boolean  enableLimit) {   
  29.          if  (sqlExecutor  instanceof  LimitSqlExecutor) {   
  30.             ((LimitSqlExecutor) sqlExecutor).setEnableLimit(enableLimit);   
  31.         }   
  32.     }   
  33.   
  34.      public   void  initialize()  throws  Exception {   
  35.          if  (sqlExecutor !=  null ) {   
  36.             SqlMapClient sqlMapClient = getSqlMapClientTemplate()   
  37.                     .getSqlMapClient();   
  38.              if  (sqlMapClient  instanceof  ExtendedSqlMapClient) {   
  39.                 ReflectUtil.setFieldValue(((ExtendedSqlMapClient) sqlMapClient)   
  40.                         .getDelegate(),  "sqlExecutor" , SqlExecutor. class ,   
  41.                         sqlExecutor);   
  42.             }   
  43.         }   
  44.     }   
  45.   
  46.     ...   
  47.   
  48. }  
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的实现代码:

Java代码 复制代码
  1. package  com.aladdin.util;   
  2.   
  3. import  java.lang.reflect.Field;   
  4. import  java.lang.reflect.Method;   
  5. import  java.lang.reflect.Modifier;   
  6.   
  7. import  org.apache.commons.logging.Log;   
  8. import  org.apache.commons.logging.LogFactory;   
  9.   
  10. public   class  ReflectUtil {   
  11.   
  12.      private   static   final  Log logger = LogFactory.getLog(ReflectUtil. class );   
  13.   
  14.      public   static   void  setFieldValue(Object target, String fname, Class ftype,   
  15.             Object fvalue) {   
  16.          if  (target ==  null   
  17.                 || fname ==  null   
  18.                 ||  "" .equals(fname)   
  19.                 || (fvalue !=  null  && !ftype.isAssignableFrom(fvalue.getClass()))) {   
  20.              return ;   
  21.         }   
  22.         Class clazz = target.getClass();   
  23.          try  {   
  24.             Method method = clazz.getDeclaredMethod( "set"   
  25.                     + Character.toUpperCase(fname.charAt( 0 ))   
  26.                     + fname.substring( 1 ), ftype);   
  27.              if  (!Modifier.isPublic(method.getModifiers())) {   
  28.                 method.setAccessible( true );   
  29.             }   
  30.             method.invoke(target, fvalue);   
  31.   
  32.         }  catch  (Exception me) {   
  33.              if  (logger.isDebugEnabled()) {   
  34.                 logger.debug(me);   
  35.             }   
  36.              try  {   
  37.                 Field field = clazz.getDeclaredField(fname);   
  38.                  if  (!Modifier.isPublic(field.getModifiers())) {   
  39.                     field.setAccessible( true );   
  40.                 }   
  41.                 field.set(target, fvalue);   
  42.             }  catch  (Exception fe) {   
  43.                  if  (logger.isDebugEnabled()) {   
  44.                     logger.debug(fe);   
  45.                 }   
  46.             }   
  47.         }   
  48.     }   
  49. }  
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代码 复制代码
  1. <? xml   version = "1.0"   encoding = "UTF-8" ?>   
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"   
  3.     "http://www.springframework.org/dtd/spring-beans.dtd" >   
  4.   
  5. < beans >   
  6.      <!-- Transaction manager for a single JDBC DataSource -->   
  7.      < bean   id = "transactionManager"   class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >   
  8.          < property   name = "dataSource" >   
  9.              < ref   bean = "dataSource"   />   
  10.          </ property >   
  11.      </ bean >   
  12.        
  13.      <!-- SqlMap setup for iBATIS Database Layer -->   
  14.      < bean   id = "sqlMapClient"   class = "org.springframework.orm.ibatis.SqlMapClientFactoryBean" >   
  15.          < property   name = "configLocation" >   
  16.              < value > classpath:/com/aladdin/dao/ibatis/sql-map-config.xml </ value >   
  17.          </ property >   
  18.          < property   name = "dataSource" >   
  19.              < ref   bean = "dataSource"   />   
  20.          </ property >   
  21.      </ bean >   
  22.   
  23.      < bean   id = "sqlExecutor"   class = "com.aladdin.dao.ibatis.ext.LimitSqlExecutor" >   
  24.          < property   name = "dialect" >   
  25.              < bean   class = "com.aladdin.dao.dialect.MySQLDialect"   />   
  26.          </ property >   
  27.      </ bean >   
  28.        
  29.      < bean   id = "baseDao"   abstract = "true"   class = "com.aladdin.dao.ibatis.BaseDaoiBatis"   init-method = "initialize" >   
  30.          < property   name = "dataSource" >   
  31.              < ref   bean = "dataSource"   />   
  32.          </ property >   
  33.          < property   name = "sqlMapClient" >   
  34.              < ref   bean = "sqlMapClient"   />   
  35.      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值