深入淺出Mybatis-分頁
來源:程序員人生 發布時間:2017-03-20 09:51:41 閱讀次數:8299次
Mybatis的分頁功能很弱,它是基于內存的分頁(查出所有記錄再按偏移量和limit取結果),在大數據量的情況下這樣的分頁基本上是沒有用的。本文基于插件,通過攔截StatementHandler重寫sql語句,實現數據庫的物理分頁。本文適配的mybatis版本是3.2.2。
準備
為何在StatementHandler攔截
在深入淺出MyBatis-Sqlsession章節介紹了1次sqlsession的完全履行進程,從中可以知道sql的解析是在StatementHandler里完成的,所以為了重寫sql需要攔截StatementHandler。
MetaObject簡介
在我的實現里大量使用了MetaObject這個對象,因此有必要先介紹下它。MetaObject是Mybatis提供的1個的工具類,通過它包裝1個對象后可以獲得或設置該對象的本來不可訪問的屬性(比如那些私有屬性)。它有個3個重要方法常常用到:
1) MetaObject
forObject(Object object,ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory)
2) Object
getValue(String name)
3) void
setValue(String name, Object value)
方法1)用于包裝對象;方法2)用于獲得屬性的值(支持OGNL的方法);方法3)用于設置屬性的值(支持OGNL的方法);
插件的原理
參見深入淺出Mybatis-插件原理。
有了上面這些基礎知識的準備后,就能夠我們的主題了。
攔截器簽名
-
@Intercepts({@Signature(type =StatementHandler.class, method = "prepare", args ={Connection.class})})
-
publicclass PageInterceptor implementsInterceptor {
-
...
-
}
從簽名里可以看出,要攔截的目標類型是StatementHandler(注意:type只能配置成接口類型),攔截的方法是名稱為prepare參數為Connection類型的方法。
intercept的實現
-
public Object intercept(Invocation invocation) throws Throwable {
-
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
-
MetaObject metaStatementHandler = MetaObject.forObject(statementHandler,
-
DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);
-
-
-
while (metaStatementHandler.hasGetter("h")) {
-
Object object = metaStatementHandler.getValue("h");
-
metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY,
-
DEFAULT_OBJECT_WRAPPER_FACTORY);
-
}
-
-
while (metaStatementHandler.hasGetter("target")) {
-
Object object = metaStatementHandler.getValue("target");
-
metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY,
-
DEFAULT_OBJECT_WRAPPER_FACTORY);
-
}
-
Configuration configuration = (Configuration) metaStatementHandler.
-
getValue("delegate.configuration");
-
dialect = configuration.getVariables().getProperty("dialect");
-
if (null == dialect || "".equals(dialect)) {
-
logger.warn("Property dialect is not setted,use default 'mysql' ");
-
dialect = defaultDialect;
-
}
-
pageSqlId = configuration.getVariables().getProperty("pageSqlId");
-
if (null == pageSqlId || "".equals(pageSqlId)) {
-
logger.warn("Property pageSqlId is not setted,use default '.*Page$' ");
-
pageSqlId = defaultPageSqlId;
-
}
-
MappedStatement mappedStatement = (MappedStatement)
-
metaStatementHandler.getValue("delegate.mappedStatement");
-
-
-
if (mappedStatement.getId().matches(pageSqlId)) {
-
BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
-
Object parameterObject = boundSql.getParameterObject();
-
if (parameterObject == null) {
-
throw new NullPointerException("parameterObject is null!");
-
} else {
-
-
PageParameter page = (PageParameter) metaStatementHandler
-
.getValue("delegate.boundSql.parameterObject.page");
-
String sql = boundSql.getSql();
-
-
String pageSql = buildPageSql(sql, page);
-
metaStatementHandler.setValue("delegate.boundSql.sql", pageSql);
-
-
metaStatementHandler.setValue("delegate.rowBounds.offset",
-
RowBounds.NO_ROW_OFFSET);
-
metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);
-
Connection connection = (Connection) invocation.getArgs()[0];
-
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈