数据库分页插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| @Intercepts({ @Signature( type = Executor.class, // 目标类 method = "query", // 目标方法 args ={MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class} ) }) public class MySqlPagingPlugin implements Interceptor { private static final Integer MAPPED_STATEMENT_INDEX = 0; private static final Integer PARAMETER_INDEX = 1; private static final Integer ROW_BOUNDS_INDEX = 2; @Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); RowBounds rb = (RowBounds) args[ROW_BOUNDS_INDEX]; // 无需分页 if (rb == RowBounds.DEFAULT) { return invocation.proceed(); } // 将原 RowBounds 参数设为 RowBounds.DEFAULT,关闭 MyBatis 内置的分页机制 args[ROW_BOUNDS_INDEX] = RowBounds.DEFAULT; MappedStatement ms = (MappedStatement) args[MAPPED_STATEMENT_INDEX]; BoundSql boundSql = ms.getBoundSql(args[PARAMETER_INDEX]); // 获取 SQL 语句,拼接 limit 语句 String sql = boundSql.getSql(); String limit = String.format( "LIMIT %d,%d", rb.getOffset(), rb.getLimit()); sql = sql + " " + limit; // 创建一个 StaticSqlSource,并将拼接好的 sql 传入 SqlSource sqlSource = new StaticSqlSource( ms.getConfiguration(), sql, boundSql.getParameterMappings()); // 通过反射获取并设置 MappedStatement 的 sqlSource 字段 Field field = MappedStatement.class.getDeclaredField("sqlSource"); field.setAccessible(true); field.set(ms, sqlSource); // 执行被拦截方法 return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } }
|
上面的分页插件通过 RowBounds 参数获取分页信息,并生成相应的 limit 语句。之后拼
接 sql,并使用该 sql 作为参数创建StaticSqlSource。最后通过反射替换MappedStatement 对象中的 sqlSource 字段。
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public interface StudentDao { List<Student> findByPaging(@Param("id") Integer id, RowBounds rb); }
<mapper namespace="xyz.coolblog.chapter7.dao.StudentDao"> <select id="findByPaging" resultType="xyz.coolblog.chapter7.model.Student"> SELECT `id`, `name`, `age` FROM student WHERE id > #{id} </select> </mapper>
public class PluginTest { private SqlSessionFactory sqlSessionFactory; @Before public void prepare() throws IOException { String resource = "chapter7/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream); inputStream.close(); } @Test public void testPlugin() { SqlSession session = sqlSessionFactory.openSession(); try { StudentDao studentDao = session.getMapper(StudentDao.class); studentDao.findByPaging(1, new RowBounds(20, 10)); } finally { session.close(); } } }
|
SQL 语句中包含了 LIMIT 字样,这说明插件生效了