Mybatis pagination entry point
There is a concept of plugins (plugins) in Mybatis, which is essentially an interceptor idea. The specific analysis can be found in the research on the principle of MyBatis interceptor in another article. On this basis, this article will directly display the implementation code of the actual project and other related analysis.
Paging specific code implementation
First we can define dialect abstract class to implement pagination AbstractDialect.java
public abstract class AbstractDialect{ /** * Whether limit and offset are supported* @return */ public abstract boolean supportLimitOffset(); /** * Whether limit is supported * @return */ public abstract boolean supportLimit(); /** * Get SQL after adding paging attributes * @param sql * @param offset * @param limit * @return */ public abstract String getLimitString(String sql, int offset, int limit);}Furthermore, we will implement the page paging technology of Oracle and Mysql database separately.
MySQLDialect.java-Mysql pagination dialect
public class MySQLDialect extends AbstractDialect { public boolean supportsLimitOffset() { return true; } public boolean supportsLimit() { return true; } public String getLimitString(String sql, int offset, int limit) { if (offset > 0) { return sql + " limit " + offset + "," + limit; } else { return sql + " limit " + limit; } }}OracleDialect.java-Oracle dialect implementation
public class OracleDialect extends ADialect{ @Override public boolean supportLimitOffset() { return false; } @Override public boolean supportLimit() { return false; } @Override public String getLimitString(String sql, int start, int limit) { if(start < 0){ start = 0; } if(limit < 0){ limit = 10; } StringBuilder pageSql = new StringBuilder(100); pageSql.append("select * from ( select temp.*, rownum row_id from ( "); pageSql.append(sql); pageSql.append(" ) temp where rownum <= ").append(start+limit); pageSql.append(") where row_id > ").append(start); return pageSql.toString(); }}The corresponding Mybatis plug-in interceptor implementation is as follows: Intercept StatementHandler#prepare(Connection con) to create SQL statement object method
PaginationInterceptor.java
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) }) public final class PaginationInterceptor implements Interceptor { private final static Logger log = LoggerFactory .getLogger(PaginationInterceptor.class); private ADialect dialect; public void setDialect(ADialect dialect) { this.dialect = dialect; } @Override public Object intercept(Invocation invocation) throws Throwable { // Directly obtain the intercepted object, which implements the class RoutingStatementHandler StatementHandler statementHandler = (StatementHandler) invocation .getTarget(); BoundSql boundSql = statementHandler.getBoundSql(); // Get metaobject, mainly used to obtain the object and attributes associated with statementHandler MetaObject metaStatementHandler = MetaObject.forObject( statementHandler, new DefaultObjectFactory(), new DefaultObjectWrapperFactory()); MappedStatement mappedStmt= (MappedStatement) metaStatementHandler .getValue("delegate.mappedStatement".intern()); // Only paginate the queryPagination() method if(mappedStmt.getId().indexOf("queryPagination")==-1){ return invocation.proceed(); } // Reconstruct the paging sql String originalSql = (String) metaStatementHandler .getValue("delegate.boundSql.sql".intern()); metaStatementHandler.setValue("delegate.boundSql.sql".intern(), dialect .getLimitString(originalSql, rowBounds.getOffset(), rowBounds.getLimit())); metaStatementHandler.setValue("delegate.rowBounds.offset".intern(), RowBounds.NO_ROW_OFFSET); metaStatementHandler.setValue("delegate.rowBounds.limit".intern(), RowBounds.NO_ROW_LIMIT); log.debug("page sql : " + boundSql.getSql()); return invocation.proceed(); } // Intercept object @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { }}The corresponding XML configuration of Spring can be as follows, taking oracle pagination as an example
<!-- oracle dialect configuration, used for oracle pagination--> <bean id="paginationInterceptor" > <property name="dialect"> <bean /> </property> </bean>
Use the above code and configuration to complete the pagination operation of the oracle database and the mysql database. And the blogger analyzes one of the points
Mybatis#MetaObject-Metadata Object Analysis
When the blogger used the above code, he was puzzled by the MetaObject class. It can directly obtain all the associated properties of the object being proxyed through the getValue() method. We can follow the source code to learn more
MetaObject#forObject()
All proxy objects enter through this static method
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) { if (object == null) { return SystemMetaObject.NULL_META_OBJECT; } else { return new MetaObject(object, objectFactory, objectWrapperFactory); } }We can directly observe the constructor, here's the mystery
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) { this.originalObject = object; this.objectFactory = objectFactory; this.objectWrapperFactory = objectWrapperFactory; // All attribute acquisitions are obtained through the objectWrapper class. Here, we mainly judge the object object type that is proxyed if (object instanceof ObjectWrapper) { this.objectWrapper = (ObjectWrapper) object; } else if (objectWrapperFactory.hasWrapperFor(object)) { this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object); } else if (object instanceof Map) { this.objectWrapper = new MapWrapper(this, (Map) object); } else if (object instanceof Collection) { this.objectWrapper = new CollectionWrapper(this, (Collection) object); } else { // What we often use is BeanWrapper this.objectWrapper = new BeanWrapper(this, object); } }To understand more infiltrate, we continue to follow up, and finally we learned that it will call the constructor function of the Reflector class
private Reflector(Class<?> clazz) { type = clazz; // Get the constructor class addDefaultConstructor(clazz); // Get the get method set addGetMethods(clazz); // Get the set method set addSetMethods(clazz); // Get the internal property set addFields(clazz); readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]); writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]); for (String propName : readablePropertyNames) { caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } for (String propName : writeablePropertyNames) { caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } } From this we can know that using the Reflector proxy class and MetaObject, you can traverse all the attributes associated with the proxy class. Take RoutingStatementHandler class as an example. After the above operation, you can access the internal attribute delegate and the internal attributes of the delegate configuration/objectFactory/typeHandlerRegistry/resultSetHandler/parameterHandler/mappedStatement and other attributes.
MetaObject#getValue()
The above explains how to proxy the internal properties of the proxy class. We can also take a brief look at how to call it correctly.
public Object getValue(String name) { // PropertyTokenizer is similar to StringTokenizer, except that the former is written as delimiter PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return null; } else { return metaValue.getValue(prop.getChildren()); } } else { return objectWrapper.get(prop); } } The specific analysis will not be explained here. How to obtain the sql string owned by StatementHandler can be obtained by getValue("delegate.boundSql.sql") and the attributes in it must be internal attributes (case sensitive).
MetaObject#setValue()
The principle is the same as MetaObject#getValue() method
Summarize
The above is the tutorial on using Spring Mybatis paging plug-in introduced to you by the editor. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. Thank you very much for your support to Wulin.com website!