[Java] [MyBatis] physical paging implementation
Mybatis3.0 has been out for a while. In fact, I like this persistence framework because it is simple and practical and has a low learning cost. The overall structure of Mybatis3.0 is similar to that of ibatis2.X. The improved features are as follows:
1. xml parsing introduces Xpath, not as amateur as ibatis2.x
2. dynamic SQL parsing with OGNL
3. adding annotations to configure SQL does not feel very useful. I prefer the xml method, code and configuration separation, which is also the original intention of ibatis.
4. enhanced the caching function. Mybatis3.0 segments the cache module into "prepetual" and "eviction" to better combine and expand the cache functions.
5. The plug-in function is finally added, just like struts, so that the internal Executor, StatementHandler, and so on can be well expanded .... And other internal object functions.
The paging function of MyBatis is based on memory paging (Find all records and retrieve the offset records. If the jdbc drive supports the absolute location or rs. next () to the specified offset locationIn fact, such paging implementation is basically useless, especially in the case of a large amount of data. However, we can use the plugin function to expand the paging function of MyBatis and implement physical paging. The procedure is as follows:
1. Compile the paging plug-in class:
/*** Copyright: Huaxin software * Project name: ACWS framework class * Creator: Wangdf * creation date: 2014-4-2 * file Description: ACWS framework paging interface class */package framework. core. interceptor; import java. SQL. connection; import java. util. map; import java. util. properties; import org. apache. commons. collections. mapUtils; import org.apache.ibatis.exe cutor. statement. statementHandler; import org. apache. ibatis. mapping. boundSql; import org. apache. ibatis. plugin. interceptor; import org. apache. ibatis. plugin. intercepts; import org. apache. ibatis. plugin. invocation; import org. apache. ibatis. plugin. plugin; import org. apache. ibatis. plugin. signature; import org. apache. ibatis. reflection. metaObject; import org. apache. ibatis. reflection. factory. defaultObjectFactory; import org. apache. ibatis. reflection. factory. objectFactory; import org. apache. ibatis. reflection. wrapper. defaultObjectWrapperFactory; import org. apache. ibatis. reflection. wrapper. objectWrapperFactory; import org. apache. ibatis. session. configuration; import org. apache. ibatis. session. rowBounds; import framework. core. util. DBUtil;/*** ACWS framework paging interface class * @ author Wangdf **/@ Intercepts ({@ Signature (type = StatementHandler. class, method = "prepare", args = {Connection. class}) public class PaginationInterceptor implements Interceptor {private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory (); private static final ObjectWrapperFactory vertex = new DefaultObjectWrapperFactory (); @ Overridepublic Object intercept (Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation. getTarget (); MetaObject metaStatementHandler = MetaObject. forObject (statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY); RowBounds rowBounds = (RowBounds) metaStatementHandler. getValue ("delegate. rowBounds "); if (rowBounds = null | rowBounds = RowBounds. DEFAULT) {return invocation. proceed ();} // separate the proxy object chain (because the target class may be intercepted by multiple interceptors, multiple proxies are formed, the following two loops can be used to separate the original target class.) while (metaStatementHandler. hasGetter ("h") {Object object = metaStatementHandler. getValue ("h"); metaStatementHandler = MetaObject. forObject (object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);} // separates the target class of the last proxy object while (metaStatementHandler. hasGetter ("target") {Object object = metaStatementHandler. getValue ("target"); metaStatementHandler = MetaObject. forObject (object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);} BoundSql boundSql = (BoundSql) metaStatementHandler. getValue ("delegate. boundSql "); String SQL = boundSql. getSql (); StringBuffer sbSql = new StringBuffer (); // rewrite sqlConfiguration configuration = (Configuration) metaStatementHandler. getValue ("delegate. configuration "); DBUtil dbUtil = new DBUtil (configuration); if (dbUtil. isMySQL () {sbSql. append (SQL ). append ("LIMIT "). append (rowBounds. getOffset ()). append (","). append (rowBounds. getLimit (); metaStatementHandler. setValue ("delegate. boundSql. SQL ", sbSql. toString (); // after the physical paging is used, the mybatis memory paging is not required. Therefore, reset the following two parameters: metaStatementHandler. setValue ("delegate. rowBounds. offset ", RowBounds. NO_ROW_OFFSET); metaStatementHandler. setValue ("delegate. rowBounds. limit ", RowBounds. NO_ROW_LIMIT);} else if (dbUtil. isOracle () {sbSql. append ("SELECT *"); sbSql. append ("FROM (select rownum rn, NOPAGESQL. * "); sbSql. append ("FROM ("). append (SQL ). append (") NOPAGESQL"); sbSql. append ("where rownum <= "). append (rowBounds. getLimit () + rowBounds. getOffset ()). append (")"); sbSql. append ("where rn> = "). append (rowBounds. getOffset (); metaStatementHandler. setValue ("delegate. boundSql. SQL ", sbSql. toString (); // after the physical paging is used, the mybatis memory paging is not required. Therefore, reset the following two parameters: metaStatementHandler. setValue ("delegate. rowBounds. offset ", RowBounds. NO_ROW_OFFSET); metaStatementHandler. setValue ("delegate. rowBounds. limit ", RowBounds. NO_ROW_LIMIT);} else {}// give the execution permission to the next interceptor return invocation. proceed () ;}@ Overridepublic Object plugin (Object target) {// The target class is packaged when the target class is of the StatementHandler type. Otherwise, the target class is directly returned, reduce the number of times the target is proxy if (target instanceof StatementHandler) {return Plugin. wrap (target, this) ;}else {return target ;}@ Overridepublic void setProperties (Properties properties Properties) {// TODO Auto-generated method stub }}
2. Configure read class
/*** Copyright: Huaxin software * Project name: ACWS framework class * Creator: Wangdf * creation date: 2014-4-2 * file Description: ACWS framework database tool class */package framework. core. util; import org. apache. commons. lang. stringUtils; import org. apache. ibatis. session. configuration; import org. slf4j. logger; import org. slf4j. loggerFactory;/*** ACWS framework database tool class * @ author Wangdf */public class DBUtil {private static final String DBTYPE_MYSQL = "MySQL"; // supported types: MySQL, oracleprivate s Tatic final String DBTYPE_ORACLE = "Oracle"; // supported types: MySQL, Oracleprivate static Logger logger = LoggerFactory. getLogger (DBUtil. class); private Configuration configuration = null; private String dbType = ""; private String defaultDateFormat = ""; public DBUtil (Configuration configuration) {if (Configuration = null) {logger. error ("failed to start the system: the MyBatis Configuration object is blank! "); Throw new IllegalArgumentException (" system startup failed: MyBatis Configuration object is blank! ");} This. configuration = configuration; this. dbType = this. configuration. getVariables (). getProperty ("dbtype"); if (StringUtils. isBlank (dbType) {logger. error ("the database type is not configured! ");} Else {logger.info (" Database Type: "+ dbType);} this. defadatedateformat = this. configuration. getVariables (). getProperty ("defadatedateformat"); if (StringUtils. isBlank (this. defadatedateformat) {this. defaultDateFormat = "yyyy-MM-dd"; logger.info ("the default database Date Format String is not specified! System Default Value: yyyy-MM-dd ");} else {logger.info (" database date default Format String: "+ this. defaultDateFormat) ;}}/*** determines whether the database is an Oracle database * @ return * @ author wangdf */public boolean isOracle () {return DBTYPE_ORACLE.equals (this. dbType);}/*** determine whether it is a MySQL database * @ return * @ author wangdf */public boolean isMySQL () {return DBTYPE_MYSQL.equals (this. dbType);}/*** obtain the database type * @ return * @ author wangdf */public String getDbType () {return this. dbType;}/*** get the default date format * @ return * @ author wangdf */public String getdefadatedateformat () {return this. defadatedateformat ;}}
3. Set in the mybatis global configuration file
<? Xml version = "1.0" encoding = "UTF-8"?> <! DOCTYPE configuration PUBLIC "-// mybatis.org//DTD Config 3.0/EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties> <property name = "dbtype" value = "MySQL"/> <! -- Database Type: mySQL, Oracle --> <property name = "defaultDateFormat" value = "yyyy-MM-dd"/> </properties> <settings> <setting name = "cacheEnabled" value =" true "/> <setting name =" lazyLoadingEnabled "value =" true "/> <setting name =" multipleResultSetsEnabled "value =" true "/> <setting name =" useColumnLabel "value = "true"/> <setting name = "defaultExecutorType" value = "REUSE"/> <setting name = "defaultStatementTimeout" value = "25000"/> </settings> <plugins> <plugin interceptor = "framework. core. interceptor. paginationInterceptor "> </plugin> </plugins> </configuration>