若是想要將現有的select語句改成支持分頁功能的查詢語句該怎麼作呢?
最簡單的一種作法就是將全部的select語句都加上limit來實現分頁,這種作法有什麼問題呢?java
有沒有一種簡便方法實現呢?
Mybatis提供了plugin機制,容許咱們在Mybatis的原有處理流程上加入本身邏輯,全部咱們就可使用這種邏輯加上咱們的分頁邏輯,也就是實現攔截器。
Mybatis支持的攔截的接口有4個,Executor、ParameterHandler、ResultSetHandler、StatementHandler。關於分頁攔截器的配置和使用後期我會更新。
mysql
Mybatis的一個插件,PageHelper,很是方便mybatis分頁查詢。國內牛人的一個開源項目,有興趣的能夠去看源碼。在github上倉庫地址爲:Mybatis-PageHelper。它支持基本主流與經常使用的數據庫,這能夠在它的文檔上看到。這裏記錄一下使用的基本方法。PageHelpe開源地址:
github項目地址:https://github.com/pagehelper/Mybatis-PageHelper
碼雲 項目地址:http://git.oschina.net/free/Mybatis_PageHelpergit
首先引入jar包依賴 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.4</version> </dependency>
在mybatis的全局配置文件SqlMapConfig.xml中配置該插件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 配置分頁插件 --> <plugins> <plugin interceptor="com.github.pagehelper.PageHelper"> <!-- 設置數據庫類型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六種數據庫--> <property name="dialect" value="mysql"/> </plugin> </plugins> </configuration>
dao層:github
public List<User> queryUserListLikeName(@Param("name") String name);
mapper.xml:sql
<select id="queryUserListLikeName" parameterType="String" resultType="User"> SELECT * FROM tb_user WHERE name LIKE '%${name}%' </select>
service.java
數據庫
public PageInfo<User> testQueryUserListLikeName() { //設置分頁條件,Parameters:pageNum 頁碼pageSize 每頁顯示數量count 是否進行count查詢 PageHelper.startPage(1, 3, true); List<User> users = this.userMapper.queryUserListLikeName(null); //取分頁後結果 PageInfo<User> pageInfo = new PageInfo<User>(users); //打印分頁信息 System.out.println("數據總數:" + pageInfo.getTotal()); System.out.println("數據總頁數:" + pageInfo.getPages()); System.out.println("最後一頁:" + pageInfo.getLastPage()); return pageInfo; }
pageInfo.java安全
public class PageInfo<T> implements Serializable { private static final long serialVersionUID = 1L; //當前頁 private int pageNum; //每頁的數量 private int pageSize; //當前頁的數量 private int size; //因爲startRow和endRow不經常使用,這裏說個具體的用法 //能夠在頁面中"顯示startRow到endRow 共size條數據" //當前頁面第一個元素在數據庫中的行號 private int startRow; //當前頁面最後一個元素在數據庫中的行號 private int endRow; //總記錄數 private long total; //總頁數 private int pages; //結果集 private List<T> list; //前一頁 private int prePage; //下一頁 private int nextPage; //是否爲第一頁 private boolean isFirstPage = false; //是否爲最後一頁 private boolean isLastPage = false; //是否有前一頁 private boolean hasPreviousPage = false; //是否有下一頁 private boolean hasNextPage = false; //導航頁碼數 private int navigatePages; //全部導航頁號 private int[] navigatepageNums; //導航條上的第一頁 private int navigateFirstPage; //導航條上的最後一頁 private int navigateLastPage; public PageInfo() { } /** * 包裝Page對象 * * @param list */ public PageInfo(List<T> list) { this(list, 8); } /** * 包裝Page對象 * * @param list page結果 * @param navigatePages 頁碼數量 */ public PageInfo(List<T> list, int navigatePages) { if (list instanceof Page) { Page page = (Page) list; this.pageNum = page.getPageNum(); this.pageSize = page.getPageSize(); this.pages = page.getPages(); this.list = page; this.size = page.size(); this.total = page.getTotal(); //因爲結果是>startRow的,因此實際的須要+1 if (this.size == 0) { this.startRow = 0; this.endRow = 0; } else { this.startRow = page.getStartRow() + 1; //計算實際的endRow(最後一頁的時候特殊) this.endRow = this.startRow - 1 + this.size; } } else if (list instanceof Collection) { this.pageNum = 1; this.pageSize = list.size(); this.pages = this.pageSize > 0 ? 1 : 0; this.list = list; this.size = list.size(); this.total = list.size(); this.startRow = 0; this.endRow = list.size() > 0 ? list.size() - 1 : 0; } if (list instanceof Collection) { this.navigatePages = navigatePages; //計算導航頁 calcNavigatepageNums(); //計算先後頁,第一頁,最後一頁 calcPage(); //判斷頁面邊界 judgePageBoudary(); } } ....... }
PageHelper 方法使用了靜態的 ThreadLocal 參數,分頁參數和線程是綁定的。只要你能夠保證在 PageHelper 方法調用後緊跟 MyBatis 查詢方法,這就是安全的。由於 PageHelper 在 finally 代碼段中自動清除了 ThreadLocal 存儲的對象。若是代碼在進入 Executor 前發生異常,就會致使線程不可用,這屬於人爲的 Bug(例如接口方法和 XML 中的不匹配,致使找不到 MappedStatement 時), 這種狀況因爲線程不可用,也不會致使 ThreadLocal 參數被錯誤的使用。 可是若是你寫出下面這樣的代碼,就是不安全的用法: PageHelper.startPage(1, 10); List<Country> list; if(param1 != null){ list = countryMapper.selectIf(param1); } else { list = new ArrayList<Country>(); } 這種狀況下因爲 param1 存在 null 的狀況,就會致使 PageHelper 生產了一個分頁參數,可是沒有被消費,這個參數就會一直保留在這個線程上。當這個線程再次被使用時,就可能致使不應分頁的方法去消費這個分頁參數,這就產生了莫名其妙的分頁。上面這個代碼,應該寫成下面這個樣子: List<Country> list; if(param1 != null){ PageHelper.startPage(1, 10); list = countryMapper.selectIf(param1); } else { list = new ArrayList<Country>(); } 這種寫法就能保證安全。 若是你對此不放心,你能夠手動清理 ThreadLocal 存儲的分頁參數,能夠像下面這樣使用: List<Country> list; if(param1 != null){ PageHelper.startPage(1, 10); try{ list = countryMapper.selectAll(); } finally { PageHelper.clearPage(); } } else { list = new ArrayList<Country>(); }
以上就是PageHelper的基本使用,簡單方便的分頁插件。mybatis