1. 程式人生 > >mybatis下的分頁,支持所有的數據庫

mybatis下的分頁,支持所有的數據庫

支持 targe bstr dna error class ati clas 調用

大家都知道,mybatis的自帶分頁方法只是邏輯分 頁,如果數據量很大,內存一定會溢出,不知道為什麽開源組織不在裏面集成hibernate的物理分頁處理方法!在不修改mybatis源代碼的情況下, 應該怎麽使mybatis支持物理分頁呢?參考了網上的一些信息,有了下面的解決方法:以oracle為例子

1.把hibernate下的dialect包全部拷貝到mybatis包的jdbc目錄下,如下圖所示:

2.定義一個ResultSetHandler Interceptor

package cn.machi.utils;

import java.sql.Statement;
import java.util.Properties;

import org.apache.ibatis.executor.resultset.FastResultSetHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
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.session.RowBounds;

@Intercepts( {@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
public class DiclectResultSetHandlerInterceptor implements Interceptor
{

public Object intercept(Invocation invocation) throws Throwable
{
FastResultSetHandler resultSet = (FastResultSetHandler)invocation.getTarget();

RowBounds rowBounds = (RowBounds)ReflectUtil.getFieldValue(resultSet,
"rowBounds");

if (rowBounds.getLimit() > 0
&& rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT)
{
ReflectUtil.setFieldValue(resultSet, "rowBounds", new RowBounds());
}
return invocation.proceed();
}

public Object plugin(Object target)
{
return Plugin.wrap(target, this);
}

public void setProperties(Properties properties)
{
}
}

3.定義一個StatementHandler的Interceptor

package cn.machi.utils;

import java.sql.Connection;
import java.util.Properties;

import org.apache.ibatis.executor.statement.PreparedStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.jdbc.dialect.OracleDialect;
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.session.RowBounds;

@Intercepts( {@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class DiclectStatementHandlerInterceptor implements Interceptor
{

private static final String DIALECT = "org.apache.ibatis.jdbc.dialect.OracleDialect";

public Object intercept(Invocation invocation) throws Throwable
{
RoutingStatementHandler statement = (RoutingStatementHandler)invocation.getTarget();
PreparedStatementHandler handler = (PreparedStatementHandler)ReflectUtil.getFieldValue(statement,
"delegate");
RowBounds rowBounds = (RowBounds)ReflectUtil.getFieldValue(handler,
"rowBounds");

if (rowBounds.getLimit() > 0
&& rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT)
{
BoundSql boundSql = statement.getBoundSql();
String sql = boundSql.getSql();

OracleDialect dialect = (OracleDialect)Class.forName(DIALECT)
.newInstance();
sql = dialect.getLimitString(sql,
rowBounds.getOffset(),
rowBounds.getLimit());

ReflectUtil.setFieldValue(boundSql, "sql", sql);
}
return invocation.proceed();
}

public Object plugin(Object target)
{
return Plugin.wrap(target, this);
}

public void setProperties(Properties properties)
{
}
}

4.定義工具類ReflectUtil

package cn.machi.utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.apache.log4j.Logger;


public class ReflectUtil
{
private static Logger log = Logger.getLogger(ReflectUtil.class);

private static Object operate(Object obj, String fieldName,
Object fieldVal, String type)
{
Object ret = null;
try
{
// 獲得對象類型
Class<? extends Object> classType = obj.getClass();
// 獲得對象的所有屬性
Field fields[] = classType.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
Field field = fields[i];
if (field.getName().equals(fieldName))
{

String firstLetter = fieldName.substring(0, 1)
.toUpperCase(); // 獲得和屬性對應的getXXX()方法的名字
if ("set".equals(type))
{
String setMethodName = "set" + firstLetter
+ fieldName.substring(1); // 獲得和屬性對應的getXXX()方法
Method setMethod = classType.getMethod(setMethodName,
new Class[] {field.getType()}); // 調用原對象的getXXX()方法
ret = setMethod.invoke(obj, new Object[] {fieldVal});
}
if ("get".equals(type))
{
String getMethodName = "get" + firstLetter
+ fieldName.substring(1); // 獲得和屬性對應的setXXX()方法的名字
Method getMethod = classType.getMethod(getMethodName,
new Class[] {});
ret = getMethod.invoke(obj, new Object[] {});
}
return ret;
}
}
}
catch (Exception e)
{
log.warn("reflect error:" + fieldName, e);
}
return ret;
}

public static Object getVal(Object obj, String fieldName)
{
return operate(obj, fieldName, null, "get");
}

public static void setVal(Object obj, String fieldName, Object fieldVal)
{
operate(obj, fieldName, fieldVal, "set");
}


private static Method getDeclaredMethod(Object object, String methodName,
Class<?>[] parameterTypes)
{
for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
{
try
{
//superClass.getMethod(methodName, parameterTypes);
return superClass.getDeclaredMethod(methodName, parameterTypes);
}
catch (NoSuchMethodException e)
{
//Method 不在當前類定義, 繼續向上轉型
}
}

return null;
}


private static void makeAccessible(Field field)
{
if (!Modifier.isPublic(field.getModifiers()))
{
field.setAccessible(true);
}
}


private static Field getDeclaredField(Object object, String filedName)
{
for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
{
try
{
return superClass.getDeclaredField(filedName);
}
catch (NoSuchFieldException e)
{
//Field 不在當前類定義, 繼續向上轉型
}
}
return null;
}


public static Object invokeMethod(Object object, String methodName,
Class<?>[] parameterTypes, Object[] parameters)
throws InvocationTargetException
{
Method method = getDeclaredMethod(object, methodName, parameterTypes);

if (method == null)
{
throw new IllegalArgumentException("Could not find method ["
+ methodName + "] on target [" + object + "]");
}

method.setAccessible(true);

try
{
return method.invoke(object, parameters);
}
catch (IllegalAccessException e)
{

}

return null;
}


public static void setFieldValue(Object object, String fieldName,
Object value)
{
Field field = getDeclaredField(object, fieldName);

if (field == null)
throw new IllegalArgumentException("Could not find field ["
+ fieldName + "] on target [" + object + "]");

makeAccessible(field);

try
{
field.set(object, value);
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
}


public static Object getFieldValue(Object object, String fieldName)
{
Field field = getDeclaredField(object, fieldName);
if (field == null)
throw new IllegalArgumentException("Could not find field ["
+ fieldName + "] on target [" + object + "]");

makeAccessible(field);

Object result = null;
try
{
result = field.get(object);
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}

return result;
}

}

5.更新mapper configuration文件,添加如下幾條,註意plugins在整個configuration文件中的順序

<plugins>
<plugin interceptor="functionPoint.db.DiclectStatementHandlerInterceptor"/>
<plugin interceptor="functionPoint.db.DiclectResultSetHandlerInterceptor"/>
</plugins>

6.使用方法同mybatis邏輯分頁,攔截器會自動攔截執行SQL的地方,加上分頁代碼:

getSqlSession().selectList(mapId, queryKey,new RowBounds(pageId, pageSize));

mybatis下的分頁,支持所有的數據庫