您好,登錄后才能下訂單哦!
這篇文章主要介紹了Mybatis-Plus進(jìn)階分頁(yè),樂(lè)觀鎖插件,通用枚舉和多數(shù)據(jù)源實(shí)例分析的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇Mybatis-Plus進(jìn)階分頁(yè),樂(lè)觀鎖插件,通用枚舉和多數(shù)據(jù)源實(shí)例分析文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。
??MP中自帶了分頁(yè)插件的功能,只需要在配置類中進(jìn)行簡(jiǎn)單的配置即可使用分頁(yè)的相關(guān)功能。分頁(yè)插件常常與前端的分頁(yè)顯示功能相關(guān),為了在前端美觀的顯示查詢到的數(shù)據(jù),通常會(huì)使用分頁(yè)插件,將所有的數(shù)據(jù)分成許多頁(yè)一頁(yè)一頁(yè)的進(jìn)行顯示,不同頁(yè)的切換使用按鈕來(lái)完成 MP的插件配置類
@Configuration public class MybatisPlusConfiguration { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { // 創(chuàng)建一個(gè)MybatisPlus的插件攔截器 MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 創(chuàng)建分頁(yè)的插件對(duì)象并設(shè)置數(shù)據(jù)庫(kù)類型 PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); // 設(shè)置請(qǐng)求的頁(yè)面大于最大頁(yè)后操作, true調(diào)回到首頁(yè),false 繼續(xù)請(qǐng)求 默認(rèn)false paginationInnerInterceptor.setOverflow(true); // 設(shè)置分頁(yè)的單頁(yè)最多條數(shù),默認(rèn) 500 條,-1 不受限制 paginationInnerInterceptor.setMaxLimit(500L); // 將這個(gè)分頁(yè)插件添加到攔截器中并返回 interceptor.addInnerInterceptor(paginationInnerInterceptor); return interceptor; } }
自定義方法并調(diào)用分頁(yè) mapper定義方法
@Mapper @Repository public interface UserMapper extends BaseMapper<User> { /** * 通過(guò)年齡查詢用戶信息并分頁(yè)返回 * @param page 傳入一個(gè)page對(duì)象 * @param age 年齡 * @return 返回一個(gè)page對(duì)象 */ Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age); }
映射文件編寫SQL語(yǔ)句
<mapper namespace="com.xiaochen.mapper.UserMapper"> <select id="selectPageVo" resultType="com.xiaochen.domain.User"> select id,name,age,email from user where age > #{age} </select> </mapper>
測(cè)試方法調(diào)用自定義方法
@Autowired UserMapper mapper; @Test public void testpage() { // 創(chuàng)建一個(gè)page對(duì)象,設(shè)置當(dāng)前頁(yè)是第1頁(yè),每頁(yè)包含3條記錄 Page<User> page = new Page<>(2, 3); // mapper調(diào)用selectPage方法之后將結(jié)果返回給上面的page對(duì)象 // 第二個(gè)參數(shù)null的話就是查詢所有的記錄,如果有查詢條件的話就傳一個(gè)wrapper對(duì)象 mapper.selectPageVo(page, 20); // 當(dāng)前頁(yè)的數(shù)據(jù) System.out.println(page.getRecords()); // 當(dāng)前是第幾頁(yè) System.out.println(page.getCurrent()); // 總頁(yè)數(shù) System.out.println(page.getPages()); // 每頁(yè)的記錄數(shù) System.out.println(page.getSize()); // 總記錄數(shù) System.out.println(page.getTotal()); // 是否有下一頁(yè) System.out.println(page.hasNext()); // 是否有上一頁(yè) System.out.println(page.hasPrevious()); }
??要想使用樂(lè)觀鎖插件,首先要知道什么是樂(lè)觀鎖以及樂(lè)觀鎖出現(xiàn)的原因。現(xiàn)實(shí)生活中,一個(gè)管理系統(tǒng)往往不僅僅只有一個(gè)管理員,以修改商品價(jià)格為例,如果有兩個(gè)管理員小李和小王商品的原價(jià)為100,老板先是讓小李將商品的價(jià)格上調(diào)50,一段時(shí)間后讓小王將商品的價(jià)格下調(diào)20,由于小李有事耽擱,兩個(gè)人同時(shí)登錄管理系統(tǒng)獲取到商品的價(jià)格對(duì)其分別進(jìn)行修改操作。如果小李最后完成操作的話商品最終為150元,如果小王最后完成操作的話商品最終為80元,這樣的話就會(huì)造成最終的價(jià)格不是老板想要的130。 要想使用代碼實(shí)現(xiàn)上述案例的話,使用線程來(lái)實(shí)現(xiàn)的話更加真實(shí)(可以模擬兩人處理先后的不確定性),但是為了簡(jiǎn)化操作,設(shè)定最后完成操作的是小王,也即是說(shuō)最后商品的價(jià)格為80
@Test public void happyLockTest() { // 小李查詢商品的價(jià)格 Product productLi = mapper.selectById(1); // 小王查詢到商品的價(jià)格 Product productWang = mapper.selectById(1); // +50 productLi.setPrice(productLi.getPrice() + 50); mapper.updateById(productLi); // -20 productWang.setPrice(productWang.getPrice() - 20); mapper.updateById(productWang); // 查詢最終的商品價(jià)格 System.out.println("最終價(jià)格為:" + mapper.selectById(1).getPrice()); }
// 控制臺(tái)最終打印 -> 最終價(jià)格為:80
??有問(wèn)題就有解決問(wèn)題的方法,出現(xiàn)這個(gè)問(wèn)題的原因就是兩個(gè)管理員同時(shí)獲取到了商品的信息并對(duì)他進(jìn)行了修改,如果可以使用鎖限制同一時(shí)間只能有一個(gè)管理員對(duì)數(shù)據(jù)進(jìn)行修改操作的話,就可以避免這個(gè)問(wèn)題了,這就是悲觀鎖。
??不對(duì)啊,不是說(shuō)要講樂(lè)觀鎖的嘛怎么講到了悲觀鎖了?悲觀鎖將整張表鎖住了,阻止其他人對(duì)表進(jìn)行修改操作,這樣的話對(duì)效率有很大的折損。于是樂(lè)觀鎖應(yīng)運(yùn)而生,樂(lè)觀鎖允許任何人任何時(shí)候?qū)Ρ碇袛?shù)據(jù)進(jìn)行修改,只不過(guò)數(shù)據(jù)表中要添加一個(gè)字段表示數(shù)據(jù)的當(dāng)前版本號(hào),數(shù)據(jù)每經(jīng)過(guò)一次更新版本號(hào)就相應(yīng)加一,數(shù)據(jù)每次更新的時(shí)候都會(huì)帶上版本號(hào)字段作為更新的條件。這樣的話就可以避免之前的問(wèn)題了,兩人同時(shí)獲取到的版本都是0,小李修改之后就會(huì)將版本字段值加一也就是1,這時(shí)小王修改的時(shí)候就會(huì)查不到表中版本號(hào)為0的數(shù)據(jù)而無(wú)法修改。
??這樣的話就會(huì)避免修改沖突,但是還是無(wú)法得到想要的結(jié)果,于是可以對(duì)兩人的修改結(jié)果進(jìn)行判斷,如果更新操作的返回結(jié)果不是0的話就說(shuō)明更新成功,否則就再次獲取數(shù)據(jù)表中的信息(這次就是為了獲得最新的版本號(hào))再次進(jìn)行更新操作
??使用MP中的樂(lè)觀鎖插件,首先需要在配置類中將樂(lè)觀鎖插件添加到攔截器中,然后再在實(shí)體類中的版本號(hào)字段上使用@Version標(biāo)志,然后就是和平常一樣的操作數(shù)據(jù)庫(kù)即可,執(zhí)行更新操作的時(shí)候會(huì)自動(dòng)將當(dāng)前查詢到的版本號(hào)當(dāng)做條件拼接到SQL語(yǔ)句中
// 將樂(lè)觀鎖插件添加到攔截器中 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 實(shí)體類標(biāo)注版本號(hào) @Version private Integer version; // 測(cè)試方法,測(cè)試兩個(gè)人最后的修改結(jié)果 @Test public void happyLockTest() { // 小李查詢商品的價(jià)格 Product productLi = mapper.selectById(1); // 小王查詢到商品的價(jià)格 Product productWang = mapper.selectById(1); // +50 int result = 0; do { // 更新失敗,重新查詢并修改 productLi = mapper.selectById(1); productLi.setPrice(productLi.getPrice() + 50); result = mapper.updateById(productLi); } while (result == 0); // -20 do { // 更新失敗,重新查詢并修改 productWang = mapper.selectById(1); productWang.setPrice(productWang.getPrice() - 20); result = mapper.updateById(productWang); } while (result == 0); // 查詢最終的商品價(jià)格 System.out.println("最終價(jià)格為:" + mapper.selectById(1).getPrice()); }
// 控制臺(tái)最終打印 -> 最終價(jià)格為:130
??對(duì)于表中擁有固定幾個(gè)值的一些字段,可以使用枚舉類將比較簡(jiǎn)單的數(shù)字或字符存入到數(shù)據(jù)庫(kù)表中,然后將這個(gè)簡(jiǎn)單的數(shù)字或字符對(duì)應(yīng)著其具體的字符串表示,比如性別0代表女1代表男。這樣就會(huì)減輕數(shù)據(jù)庫(kù)的存儲(chǔ)壓力,提高用戶的使用體驗(yàn)。 使用MP的通用枚舉必須先創(chuàng)建一個(gè)枚舉類,向外提供屬性的getter方法和全參構(gòu)造器,并使用@EnumValue注解將標(biāo)識(shí)的屬性值在數(shù)據(jù)庫(kù)中存儲(chǔ)
@Getter @AllArgsConstructor public enum SexEnum { FEMALE(0, "女"), MALE(1, "男"); // 將注解標(biāo)識(shí)的屬性值存儲(chǔ)到數(shù)據(jù)庫(kù)中 @EnumValue private Integer sex; private String sexName; }
??然后實(shí)體類中修改字段對(duì)應(yīng)屬性的類型為枚舉類型,然后重寫toString方法,方便查詢結(jié)果顯示為數(shù)據(jù)表中數(shù)字或字符對(duì)應(yīng)的具體的字符串表示
// 修改字段對(duì)應(yīng)屬性的類型為枚舉類型 private SexEnum sex; // 重寫toString方法 @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", sex=" + sex.getSexName() + ", age=" + age + ", email='" + email + '\'' + ", isDeleted=" + isDeleted + '}'; }
??最后在配置文件中設(shè)置通用枚舉的包,也就是相當(dāng)于讓你寫的枚舉類生效
mybatis-plus: # 設(shè)置通用枚舉的包 type-enums-package: com.xiaochen.enums
測(cè)試
@Test public void enumTest() { User user = new User(); user.setName("張三"); user.setAge(23); user.setSex(SexEnum.FEMALE); mapper.insert(user); User user1 = mapper.selectById(6); System.out.println(user1); }
測(cè)試結(jié)果
??多數(shù)據(jù)源就是在一個(gè)程序中同時(shí)配置多個(gè)數(shù)據(jù)庫(kù)作為數(shù)據(jù)源進(jìn)行操作,適用于多種場(chǎng)景:純粹多庫(kù)、 讀寫分離、 一主多從、 混合模式等。目前我們就來(lái)模擬一個(gè)純粹多庫(kù)的一個(gè)場(chǎng)景,配置兩個(gè)數(shù)據(jù)庫(kù)的兩張表,通過(guò)一個(gè)測(cè)試用例分別獲取兩張表的數(shù)據(jù),如果獲取到說(shuō)明多庫(kù)模擬成功
第一步: 導(dǎo)入依賴
<!--mybatis-的場(chǎng)景啟動(dòng)器--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency>
第二步: 配置文件配置多數(shù)據(jù)源
spring:
# 配置數(shù)據(jù)源信息
datasource:
dynamic:
# 設(shè)置默認(rèn)的數(shù)據(jù)源或者數(shù)據(jù)源組,當(dāng)設(shè)置的數(shù)據(jù)源都找不到時(shí)使用默認(rèn)數(shù)據(jù)源,默認(rèn)值即為master
primary: master
# 嚴(yán)格匹配數(shù)據(jù)源,默認(rèn)false.true未匹配到指定數(shù)據(jù)源時(shí)拋異常,false匹配不到指定數(shù)據(jù)源時(shí)使用默認(rèn)數(shù)據(jù)源
strict: false
datasource:
# 主數(shù)據(jù)源
master:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus
username: root
password: 123456
# 從數(shù)據(jù)源
slave_1:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
第三步: 照常使用方法測(cè)試在兩個(gè)數(shù)據(jù)庫(kù)查詢兩張表,唯一不同的就是在service的實(shí)現(xiàn)類上使用@DS注解,標(biāo)注service實(shí)現(xiàn)類的所有方法都是對(duì)指定數(shù)據(jù)源進(jìn)行操作的
測(cè)試類及結(jié)果
關(guān)于“Mybatis-Plus進(jìn)階分頁(yè),樂(lè)觀鎖插件,通用枚舉和多數(shù)據(jù)源實(shí)例分析”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“Mybatis-Plus進(jìn)階分頁(yè),樂(lè)觀鎖插件,通用枚舉和多數(shù)據(jù)源實(shí)例分析”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。