private void pagination(Invocation invocation, StatementHandler target) throws SQLException { final MetaObject metaStatementHandler = getMetaObject(target); final BoundSql boundSql = target.getBoundSql(); Page<?> page = PAGE_THREAD_LOCAL.get(); if (page == null) { page = findPageParameter(boundSql.getParameterObject()); } // 如果传入的参数中有分页对象且sql语句中有select,才做分页处理 String sql = boundSql.getSql().toLowerCase(); if (sql.startsWith("select") && page != null) { // 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数 metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET); metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT); // 设置分页对象里的总记录数和总页数 Connection connection = (Connection) invocation.getArgs()[0]; MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); if (page.isCountTotal()) { int recordsTotal = getTotalCount(sql, connection, mappedStatement, boundSql); page.setTotalNum(recordsTotal); } // 最后重写sql String pageSql = buildPageSql(sql, page); metaStatementHandler.setValue("delegate.boundSql.sql", pageSql); } }
/** * 获取总记录数 * * @param sql 原始sql语句 * @param conn * @param ms * @param boundSql * @return * @throws SQLException */ private int getTotalCount(String sql, Connection conn, MappedStatement ms, BoundSql boundSql) throws SQLException { int start = sql.indexOf("from"); if (start == -1) { throw new RuntimeException("statement has no 'from' keyword"); } int stop = sql.indexOf("order by"); if (stop == -1) { stop = sql.length(); } String countSql = "select count(0) " + sql.substring(start, stop); BoundSql countBoundSql = new BoundSql( ms.getConfiguration(), countSql, boundSql.getParameterMappings(), boundSql.getParameterObject()); ParameterHandler parameterHandler = new DefaultParameterHandler(ms, boundSql.getParameterObject(), countBoundSql); PreparedStatement stmt = null; ResultSet rs = null; int count = 0; try { stmt = conn.prepareStatement(countSql); // 通过parameterHandler给PreparedStatement对象设置参数 parameterHandler.setParameters(stmt); rs = stmt.executeQuery(); if (rs.next()) { count = rs.getInt(1); } } finally { CloseableUtil.closeQuietly(rs); CloseableUtil.closeQuietly(stmt); } return count; }