MyBatis分頁(yè)的四種方式
MyBatis 是一個(gè)優(yōu)秀的持久層框架,它為開發(fā)人員提供了一種通過簡(jiǎn)單的 XML 或注解方式來(lái)操作數(shù)據(jù)庫(kù)的工具。在日常開發(fā)中,分頁(yè)查詢是非常常見的需求。MyBatis 提供了多種實(shí)現(xiàn)分頁(yè)的方法,主要包括以下三種:
- 物理分頁(yè)(Physical Pagination)
- 邏輯分頁(yè)(Logical Pagination)
- 使用插件分頁(yè)(Pagination with Plugins)
下面將詳細(xì)講解這三種分頁(yè)方式的原理、實(shí)現(xiàn)步驟和各自的優(yōu)缺點(diǎn)。
1、物理分頁(yè)(Physical Pagination)
物理分頁(yè)是指在 SQL 查詢中直接使用數(shù)據(jù)庫(kù)的分頁(yè)語(yǔ)法,例如 LIMIT
和 OFFSET
,通過 SQL 語(yǔ)句控制返回的數(shù)據(jù)范圍。物理分頁(yè)直接由數(shù)據(jù)庫(kù)執(zhí)行分頁(yè)操作,性能相對(duì)較好。
1.1、原理
物理分頁(yè)通過在 SQL 查詢中加入分頁(yè)條件,利用數(shù)據(jù)庫(kù)的分頁(yè)功能進(jìn)行數(shù)據(jù)截取,返回所需的數(shù)據(jù)集。例如在 MySQL 中使用 LIMIT
和 OFFSET
實(shí)現(xiàn)分頁(yè)。
1.2、實(shí)現(xiàn)步驟
1.2.1、在 XML 映射文件中配置分頁(yè) SQL:
<select id="selectUsers" parameterType="map" resultType="User"> SELECT * FROM users ORDER BY id LIMIT #{offset}, #{limit} </select>
1.2.2、在 Java 代碼中調(diào)用分頁(yè)查詢:
Map<String, Object> params = new HashMap<>(); int page = 1; // 頁(yè)碼 int pageSize = 10; // 每頁(yè)顯示條數(shù) int offset = (page - 1) * pageSize; params.put("offset", offset); params.put("limit", pageSize); List<User> users = session.selectList("selectUsers", params);
1.3、優(yōu)點(diǎn)
- 性能高:分頁(yè)操作在數(shù)據(jù)庫(kù)端完成,減少了網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)量。
- 簡(jiǎn)單直接:實(shí)現(xiàn)方式簡(jiǎn)單,直接在 SQL 中添加分頁(yè)參數(shù)。
1.4、缺點(diǎn)
- 數(shù)據(jù)庫(kù)依賴:分頁(yè)語(yǔ)法依賴于具體的數(shù)據(jù)庫(kù)實(shí)現(xiàn),不同數(shù)據(jù)庫(kù)的分頁(yè)語(yǔ)法不同。
- 代碼重復(fù):每個(gè)分頁(yè)查詢都需要重復(fù)編寫分頁(yè) SQL。
2、邏輯分頁(yè)(Logical Pagination)
邏輯分頁(yè)是指在內(nèi)存中進(jìn)行分頁(yè)操作,先查詢出所有數(shù)據(jù),然后在應(yīng)用層進(jìn)行分頁(yè)。邏輯分頁(yè)適用于數(shù)據(jù)量較小的情況,數(shù)據(jù)量較大時(shí)不推薦使用。
2.1、原理
邏輯分頁(yè)通過在應(yīng)用層對(duì)查詢結(jié)果進(jìn)行截取,返回所需的分頁(yè)數(shù)據(jù)。先執(zhí)行不帶分頁(yè)條件的查詢,獲取所有數(shù)據(jù)后,再根據(jù)分頁(yè)參數(shù)截取子集。
2.2、實(shí)現(xiàn)步驟
2.2.1、在 XML 映射文件中配置查詢 SQL:
<select id="selectAllUsers" resultType="User"> SELECT * FROM users </select>
2.2.2、在 Java 代碼中進(jìn)行邏輯分頁(yè):
List<User> allUsers = session.selectList("selectAllUsers"); int page = 1; // 頁(yè)碼 int pageSize = 10; // 每頁(yè)顯示條數(shù) int start = (page - 1) * pageSize; int end = Math.min(start + pageSize, allUsers.size()); List<User> usersPage = allUsers.subList(start, end);
2.3、優(yōu)點(diǎn)
- 數(shù)據(jù)庫(kù)無(wú)關(guān):不依賴于具體的數(shù)據(jù)庫(kù)分頁(yè)語(yǔ)法,具有良好的兼容性。
- 簡(jiǎn)單實(shí)現(xiàn):無(wú)需修改 SQL 語(yǔ)句,分頁(yè)邏輯在應(yīng)用層實(shí)現(xiàn)。
2.4、缺點(diǎn)
- 性能低:需要一次性查詢出所有數(shù)據(jù),當(dāng)數(shù)據(jù)量大時(shí)會(huì)占用大量?jī)?nèi)存,查詢性能較差。
- 適用范圍有限:僅適用于數(shù)據(jù)量較小的場(chǎng)景。
3、使用插件分頁(yè)(Pagination with Plugins)
MyBatis 支持通過插件機(jī)制實(shí)現(xiàn)分頁(yè),這種方式在性能和使用方便性上具有很大優(yōu)勢(shì)。常用的分頁(yè)插件有 PageHelper
和 MyBatis-Plus
提供的分頁(yè)插件。
3.1、原理
分頁(yè)插件通過攔截 MyBatis 執(zhí)行的 SQL 語(yǔ)句,在執(zhí)行查詢前自動(dòng)添加分頁(yè)參數(shù),從而實(shí)現(xiàn)透明的分頁(yè)功能。開發(fā)者只需配置插件并調(diào)用分頁(yè)方法,無(wú)需手動(dòng)編寫分頁(yè) SQL。
3.2、實(shí)現(xiàn)步驟(以 PageHelper 為例)
3.2.1、引入 PageHelper 依賴:
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency>
3.2.2、配置 PageHelper 插件:
@Configuration public class MyBatisConfig { @Bean public PageInterceptor pageInterceptor() { PageInterceptor pageInterceptor = new PageInterceptor(); Properties properties = new Properties(); properties.setProperty("helperDialect", "mysql"); properties.setProperty("reasonable", "true"); pageInterceptor.setProperties(properties); return pageInterceptor; } }
3.2.3、在 Java 代碼中使用分頁(yè)插件:
PageHelper.startPage(1, 10); List<User> users = session.selectList("selectUsers"); PageInfo<User> pageInfo = new PageInfo<>(users);
3.3、優(yōu)點(diǎn)
- 高性能:分頁(yè)操作在數(shù)據(jù)庫(kù)端完成,減少網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)量,性能優(yōu)于邏輯分頁(yè)。
- 使用方便:開發(fā)者無(wú)需編寫分頁(yè) SQL,只需調(diào)用插件提供的方法即可實(shí)現(xiàn)分頁(yè)功能。
- 功能豐富:插件通常提供了豐富的分頁(yè)功能,如自動(dòng)計(jì)算總記錄數(shù)、分頁(yè)導(dǎo)航等。
3.4、缺點(diǎn)
- 依賴第三方庫(kù):需要引入額外的依賴,并進(jìn)行相應(yīng)的配置。
- 學(xué)習(xí)成本:需要學(xué)習(xí)和理解插件的使用方法和配置方式。
MyBatis 提供的三種分頁(yè)方式各有優(yōu)缺點(diǎn),開發(fā)者應(yīng)根據(jù)具體的業(yè)務(wù)需求和場(chǎng)景選擇合適的分頁(yè)方式:
- 物理分頁(yè):適用于數(shù)據(jù)量較大、對(duì)性能要求較高的場(chǎng)景,分頁(yè)操作在數(shù)據(jù)庫(kù)端完成。
- 邏輯分頁(yè):適用于數(shù)據(jù)量較小、不依賴數(shù)據(jù)庫(kù)分頁(yè)語(yǔ)法的場(chǎng)景,分頁(yè)操作在應(yīng)用層完成。
- 使用插件分頁(yè):通過插件實(shí)現(xiàn)透明分頁(yè),適用于大多數(shù)場(chǎng)景,兼具高性能和易用性。
在實(shí)際開發(fā)中,建議優(yōu)先考慮使用分頁(yè)插件,因?yàn)檫@種方式既保證了高性能,又簡(jiǎn)化了開發(fā)過程。同時(shí),分頁(yè)插件通常提供了更多的功能和更好的擴(kuò)展性,能夠滿足復(fù)雜的分頁(yè)需求。無(wú)論選擇哪種分頁(yè)方式,都需要綜合考慮系統(tǒng)的性能、易用性和維護(hù)成本,做出最適合業(yè)務(wù)需求的決策。
4、RowBounds實(shí)現(xiàn)分頁(yè)
RowBounds原理
- Mybatis可以通過傳遞RowBounds對(duì)象,來(lái)進(jìn)行數(shù)據(jù)庫(kù)數(shù)據(jù)的分頁(yè)操作,然而遺憾的是,該分頁(yè)操作是對(duì)ResultSet結(jié)果集進(jìn)行分頁(yè),也就是人們常說的邏輯分頁(yè),而非物理分頁(yè)(物理分頁(yè)當(dāng)然就是我們?cè)趕ql語(yǔ)句中指定limit和offset值)。
- 不再使用SQL實(shí)現(xiàn)分頁(yè)
RowBounds使用
1、接口
List<Map> getUserByRowBounds(Map<String,Integer> map);
2、mapper.xml
<!--分頁(yè)--> <select id="getUserByRowBounds" parameterType="map" resultType="map" > select * from mybatis01.user ; </select>
3、測(cè)試
@Test public void getUserByRowBounds(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); //RowBounds實(shí)現(xiàn) RowBounds rowBounds = new RowBounds(1,2); //通過java代碼層面實(shí)現(xiàn)分頁(yè) List<Map> userList = sqlSession.selectList("com.jin.mapper.UserMapper.getUserByRowBounds", null, rowBounds); for (Map map1 : userList) { System.out.println(map1); } sqlSession.close(); }
RowBounds大坑
RowBounds是將所有符合條件的數(shù)據(jù)全都查詢到內(nèi)存中,然后在內(nèi)存中對(duì)數(shù)據(jù)進(jìn)行分頁(yè)
如我們查詢user表中id>0的數(shù)據(jù),然后分頁(yè)查詢sql如下:
select * from user where id >0 limit 3,10
但使用RowBounds后,會(huì)將id>0的所有數(shù)據(jù)都加載到內(nèi)存中,然后跳過offset=3條數(shù)據(jù),截取10條數(shù)據(jù)出來(lái),若id>0的數(shù)據(jù)有100萬(wàn),則100w數(shù)據(jù)都會(huì)被加載到內(nèi)存中,從而造成內(nèi)存OOM
。
所以當(dāng)數(shù)據(jù)量非常大時(shí),一定要慎用RowBounds類。切記!切記
!
到此這篇關(guān)于MyBatis分頁(yè)的四種方式的文章就介紹到這了,更多相關(guān)MyBatis分頁(yè)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java 同步器SynchronousQueue詳解及實(shí)例
這篇文章主要介紹了java 同步器SynchronousQueue詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05Java中l(wèi)ock和tryLock及l(fā)ockInterruptibly的區(qū)別
這篇文章主要介紹了Java中l(wèi)ock和tryLock及l(fā)ockInterruptibly的區(qū)別,文章介紹詳細(xì),具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-05-05Java實(shí)現(xiàn)的貸款金額計(jì)算功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)的貸款金額計(jì)算功能,結(jié)合實(shí)例形式分析了Java簡(jiǎn)單數(shù)值運(yùn)算及類型轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01Java對(duì)象轉(zhuǎn)json JsonFormat注解
這篇文章主要介紹了Java對(duì)象轉(zhuǎn)json JsonFormat注解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05idea全局搜索快捷鍵超詳細(xì)總結(jié)(推薦!)
在實(shí)際開發(fā)中項(xiàng)目會(huì)非常多,如何在項(xiàng)目中快速定位,你說需要找到的類或方法,可以利用idea的全局搜索功能,下面這篇文章主要給大家分享介紹了關(guān)于idea全局搜索快捷鍵超詳細(xì)總結(jié)的相關(guān)資料,需要的朋友可以參考下2023-01-01MyBatis動(dòng)態(tài)Sql之if標(biāo)簽的用法詳解
這篇文章主要介紹了MyBatis動(dòng)態(tài)Sql之if標(biāo)簽的用法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-07-07Java實(shí)戰(zhàn)項(xiàng)目 醫(yī)院預(yù)約掛號(hào)系統(tǒng)
本文是一個(gè)Java語(yǔ)言編寫的實(shí)戰(zhàn)項(xiàng)目,是一個(gè)醫(yī)院預(yù)約掛號(hào)系統(tǒng),主要用到了jdbc+jsp+mysql+ajax等技術(shù),技術(shù)含量比較高,感興趣的童鞋跟著小編往下看吧2021-09-09