javascript
MyBatis_Plus(Spring版本笔记)
目錄
- 前言
- 一、MyBatis-Plus簡(jiǎn)介
- 1.1 簡(jiǎn)介
- 1.2 特性
- 1.3 支持?jǐn)?shù)據(jù)庫(kù)
- 1.4 框架結(jié)構(gòu)
- 1.5 代碼及文檔地址
- 二、 入門案例
- 2.1 開發(fā)環(huán)境
- 2.2 創(chuàng)建數(shù)據(jù)庫(kù)和表
- 2.2.1 創(chuàng)建表
- 2.2.2 添加數(shù)據(jù)
- 2.3 創(chuàng)建maven工程
- 2.3.1 打包方式 jar
- 2.3.2 引入依賴
- 2.4 Spring整合MyBatis
- 2.4.1 創(chuàng)建實(shí)體
- 2.4.2 創(chuàng)建MyBatis的核心配置文件
- 2.4.3 創(chuàng)建mapper接口和映射文件
- 2.4.4 創(chuàng)建jdbc.properties
- 2.4.5 創(chuàng)建Spring的配置文件
- 2.4.6 添加日志功能
- 2.4.7 測(cè)試
- 2.5 加入MyBatis-Plus
- 2.5.1 創(chuàng)建Mapper接口
- 2.5.2 測(cè)試
- 2.5.3 結(jié)果
- 2.6 總結(jié)
- 三、基本CRUD
- 3.1 BaseMapper
- 3.2 BaseMapper功能測(cè)試
- 3.3 通用Service
- 3.3.1 IService
- 3.3.2 創(chuàng)建Service接口和實(shí)現(xiàn)類
- 3.3.3 在spring配置文件中設(shè)置自動(dòng)掃描service的包
- 3.3.4 測(cè)試查詢記錄條數(shù)和批量添加
- 四、常用注解
- 4.1 @TableName
- 4.1.1 問題
- 4.1.2 通過@TableName解決問題
- 4.1.3 通過GlobalConfig解決問題
- 4.2 @TableId
- 4.2.1 問題引出
- 4.2.2 通過@TableId解決問題
- 4.2.3 @TableId的value屬性
- 4.2.4 @TableId的type屬性
- 4.2.5 雪花算法
- 4.3 @TableField
- 4.4 @TableLogic(邏輯刪除)
- 4.4.1 邏輯刪除
- 4.4.2 實(shí)現(xiàn)邏輯刪除
- 五、條件構(gòu)造器和常用接口
- 5.1 wapper介紹
- 5.2 QueryWrapper
- 5.2.1 組裝查詢條件
- 5.2.2 組裝排序條件
- 5.2.3 組裝刪除條件
- 5.2.4 條件的優(yōu)先級(jí)
- 5.2.5 組裝select子句
- 5.2.6 實(shí)現(xiàn)子查詢
- 5.3 UpdateWrapper
- 5.4 condition
- 5.5 LambdaQueryWrapper
- 5.6 LambdaUpdateWrapper
- 六、插件
- 6.1 分頁插件
- 6.1.1 添加配置
- 6.1.2 測(cè)試
- 6.2 xml自定義分頁
- 6.2.1 UserMapper中定義接口方法
- 6.2.2 UserMapper.xml中編寫SQL
- 6.2.3 測(cè)試
- 6.3 樂觀鎖
- 6.3.1 場(chǎng)景
- 6.3.2 樂觀鎖與悲觀鎖
- 6.3.3 模擬修改沖突
- 6.3.4 樂觀鎖實(shí)現(xiàn)流程
- 6.3.5 Mybatis-Plus實(shí)現(xiàn)樂觀鎖
- 七 、通用枚舉
- 7.1 數(shù)據(jù)庫(kù)添加字段sex
- 7.2 創(chuàng)建通用枚舉
- 7.3 配置掃描通用枚舉
- 7.4 測(cè)試
- 八、代碼生成器
- 8.1 引入依賴
- 8.2 快速生成
- 九 、MyBatisX插件
- 9.1 安裝插件
- 9.2 功能
- 9.2.1 XML跳轉(zhuǎn)
- 9.2.2 快速生成代碼
- 十、總結(jié)
前言
本文主要參考嗶站尚硅谷楊博超講師課件整理而成,屬于自己復(fù)習(xí)使用。
提示:以下是本篇文章正文內(nèi)容,下面案例可供參考
一、MyBatis-Plus簡(jiǎn)介
1.1 簡(jiǎn)介
MyBatis-Plus(簡(jiǎn)稱 MP)是一個(gè) MyBatis的增強(qiáng)工具,在 MyBatis 的基礎(chǔ)上只做增強(qiáng)不做改變,為簡(jiǎn)化開發(fā)、提高效率而生。
愿景
我們的愿景是成為 MyBatis 最好的搭檔,就像魂斗羅中的 1P、2P,基友搭配,效率翻倍。
1.2 特性
- 無侵入:只做增強(qiáng)不做改變,引入它不會(huì)對(duì)現(xiàn)有工程產(chǎn)生影響,如絲般順滑
- 損耗小:啟動(dòng)即會(huì)自動(dòng)注入基本 CURD,性能基本無損耗,直接面向?qū)ο蟛僮?/li>
- 強(qiáng)大的 CRUD 操作:內(nèi)置通用 Mapper、通用 Service,僅僅通過少量配置即可實(shí)現(xiàn)單表大部分 CRUD 操作,更有強(qiáng)大的條件構(gòu)造器,滿足各類使用需求
- 支持 Lambda 形式調(diào)用:通過 Lambda 表達(dá)式,方便的編寫各類查詢條件,無需再擔(dān)心字段寫錯(cuò)
- 支持主鍵自動(dòng)生成:支持多達(dá) 4 種主鍵策略(內(nèi)含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解決主鍵問題
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式調(diào)用,實(shí)體類只需繼承 Model 類即可進(jìn)行強(qiáng)大的 CRUD 操作
- 支持自定義全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 內(nèi)置代碼生成器:采用代碼或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、Controller 層代碼,支持模板引擎,更有超多自定義配置等您來使用
- 內(nèi)置分頁插件:基于 MyBatis 物理分頁,開發(fā)者無需關(guān)心具體操作,配 插件之后,寫分頁等同于普通 List 查詢
- 分頁插件支持多種數(shù)據(jù)庫(kù):支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多種數(shù)據(jù)庫(kù)
- 內(nèi)置性能分析插件:可輸出 SQL 語句以及其執(zhí)行時(shí)間,建議開發(fā)測(cè)試時(shí)啟用該功能,能快速揪出慢查詢
1.3 支持?jǐn)?shù)據(jù)庫(kù)
任何能使用MyBatis進(jìn)行 CRUD, 并且支持標(biāo)準(zhǔn) SQL 的數(shù)據(jù)庫(kù),具體支持情況如下
- MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQLSQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb
- 達(dá)夢(mèng)數(shù)據(jù)庫(kù),虛谷數(shù)據(jù)庫(kù),人大金倉(cāng)數(shù)據(jù)庫(kù),南大通用(華庫(kù))數(shù)據(jù)庫(kù),南大通用數(shù)據(jù)庫(kù),神通數(shù)據(jù)庫(kù),瀚高數(shù)據(jù)庫(kù)
1.4 框架結(jié)構(gòu)
1.5 代碼及文檔地址
官方地址:http://mp.baomidou.com
代碼發(fā)布地址:
Github: https://github.com/baomidou/mybatis-plus
Gitee: https://gitee.com/baomidou/mybatis-plus
文檔發(fā)布地址:https://baomidou.com/pages/24112f
二、 入門案例
2.1 開發(fā)環(huán)境
以maven工程為例,以ssm整合為技術(shù)框架。
| IDE | idea 2021.3 |
| JDK | JDK1.8 |
| MAVEN | maven 3.8.4 |
| MySQL | MySQL8.0.25 |
| Spring | 5.3.1 |
| MyBatis-Plus | 3.4.3.4 |
2.2 創(chuàng)建數(shù)據(jù)庫(kù)和表
2.2.1 創(chuàng)建表
CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; use `mybatis_plus`; CREATE TABLE `user` ( `id` bigint(20) NOT NULL COMMENT '主鍵ID', `name` varchar(30) DEFAULT NULL COMMENT '姓名', `age` int(11) DEFAULT NULL COMMENT '年齡', `email` varchar(50) DEFAULT NULL COMMENT '郵箱', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;2.2.2 添加數(shù)據(jù)
INSERT INTO user (id, name, age, email) VALUES (1, 'Jone', 18, 'test1@baomidou.com'), (2, 'Jack', 20, 'test2@baomidou.com'), (3, 'Tom', 28, 'test3@baomidou.com'), (4, 'Sandy', 21, 'test4@baomidou.com'), (5, 'Billie', 24, 'test5@baomidou.com');2.3 創(chuàng)建maven工程
2.3.1 打包方式 jar
<packaging>jar</packaging>2.3.2 引入依賴
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency><!-- 連接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><!-- junit測(cè)試 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- MySQL驅(qū)動(dòng) --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version></dependency><!-- 日志 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.30</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency><!-- lombok用來簡(jiǎn)化實(shí)體類 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.16</version></dependency><!--MyBatis-Plus的核心依賴--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>3.4.3.4</version></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>test</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency></dependencies><properties><spring.version>5.3.1</spring.version></properties>注意:
Spring整合MyBatis,需要MyBatis以及Spring整合MyBatis的依賴:
但是,在以上的依賴列表中,并沒有MyBatis以及Spring整合MyBatis的依賴,因?yàn)楫?dāng)我們引入了
MyBatis-Plus的依賴時(shí),就可以間接的引入這些依賴
并且依賴和依賴之間的版本必須兼容,所以我們不能隨便引入其他版本的依賴,以免發(fā)生沖突
在官網(wǎng)上有明確提示:
2.4 Spring整合MyBatis
2.4.1 創(chuàng)建實(shí)體
public class User {private Long id;private String name;private int age;private String email;public User(Long id, String name, int age, String email) {this.id = id;this.name = name;this.age = age;this.email = email;}public User() {}public Long getId() {return this.id;}public String getName() {return this.name;}public int getAge() {return this.age;}public String getEmail() {return this.email;}public SexEnum getSex() {return this.sex;}public int getIsDeleted() {return this.isDeleted;}public void setId(Long id) {this.id = id;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public void setEmail(String email) {this.email = email;}public void setSex(SexEnum sex) {this.sex = sex;}public void setIsDeleted(int isDeleted) {this.isDeleted = isDeleted;}public String toString() {return "User(id=" + this.getId() + ", name=" + this.getName() + ", age=" + this.getAge() + ", email=" + this.getEmail() + ", sex=" + this.getSex() + ", isDeleted=" + this.getIsDeleted() + ")";} }2.4.2 創(chuàng)建MyBatis的核心配置文件
在resources下創(chuàng)建mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration></configuration>2.4.3 創(chuàng)建mapper接口和映射文件
- mapper接口:
- mapper映射文件:
在resources下的com/atguigu/mp/mapper目錄下創(chuàng)建TestMapper.xml
2.4.4 創(chuàng)建jdbc.properties
在resources下創(chuàng)建jdbc.properties
jdbc.username=root jdbc.password=5864@WCY jdbc.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false jdbc.driver=com.mysql.cj.jdbc.Driver2.4.5 創(chuàng)建Spring的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!-- 引入jdbc.properties --><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!-- 配置Druid數(shù)據(jù)源 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置用于創(chuàng)建SqlSessionFactory的工廠bean --><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!-- 設(shè)置MyBatis配置文件的路徑(可以不設(shè)置) --><property name="configLocation" value="classpath:mybatis-config.xml"></property><!-- 設(shè)置數(shù)據(jù)源 --><property name="dataSource" ref="dataSource"></property><!-- 設(shè)置類型別名所對(duì)應(yīng)的包 --><property name="typeAliasesPackage" value="com.atguigu.mybatisplus.pojo"></property><!--設(shè)置映射文件的路徑若映射文件所在路徑和mapper接口所在路徑一致,則不需要設(shè)置--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/></bean><!--配置mapper接口的掃描配置由mybatis-spring提供,可以將指定包下所有的mapper接口創(chuàng)建動(dòng)態(tài)代理并將這些動(dòng)態(tài)代理作為IOC容器的bean管理--><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.atguigu.mybatisplus.mapper"></property></bean><!--配置自動(dòng)掃描的包--><context:component-scan base-package="com.atguigu.mybatisplus.service"></context:component-scan> </beans>2.4.6 添加日志功能
在resources下創(chuàng)建logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"><!--定義日志文件的存儲(chǔ)地址 logs為當(dāng)前項(xiàng)目的logs目錄 還可以設(shè)置為../logs --><property name="LOG_HOME" value="logs" /><!--控制臺(tái)日志, 控制臺(tái)輸出 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級(jí)別從左顯示5個(gè)字符寬度,%msg:日志消息,%n是換行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}- %msg%n</pattern></encoder></appender><!--myibatis log configure--><logger name="com.apache.ibatis" level="TRACE"/><logger name="java.sql.Connection" level="DEBUG"/><logger name="java.sql.Statement" level="DEBUG"/><logger name="java.sql.PreparedStatement" level="DEBUG"/><!-- 日志輸出級(jí)別 --><root level="DEBUG"><appender-ref ref="STDOUT" /></root></configuration>2.4.7 測(cè)試
- 方式一:通過IOC容器
- 方式二 Spring整合junit
2.5 加入MyBatis-Plus
Spring整合MyBatis
加入MyBatis-Plus之后
此處使用的是MybatisSqlSessionFactoryBean
經(jīng)觀察,目前bean中配置的屬性和SqlSessionFactoryBean一致
MybatisSqlSessionFactoryBean是在SqlSessionFactoryBean的基礎(chǔ)上進(jìn)行了增強(qiáng)
即具有SqlSessionFactoryBean的基礎(chǔ)功能,又具有MyBatis-Plus的擴(kuò)展配置
具體配置信息地址(https://baomidou.com/pages/56bac0/#%E5%9F%BA%E6%9C%AC%E9%
85%8D%E7%BD%AE)
2.5.1 創(chuàng)建Mapper接口
public interface UserMapper extends BaseMapper<User> { }BaseMapper是MyBatis-Plus提供的基礎(chǔ)mapper接口,泛型為所操作的實(shí)體類型,其中包含CRUD的各個(gè)方法,我們的mapper繼承了BaseMapper之后,就可以直接使用BaseMapper所提供的各種方法,而不需要編寫映射文件以及SQL語句,大大的提高了開發(fā)效率
2.5.2 測(cè)試
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisPlusTest {/*沒有使用mybatis_plus@Testpublic void testMyBatis(){ApplicationContext ac = newClassPathXmlApplicationContext("applicationContext.xml");UserMapper mapper = ac.getBean(UserMapper.class);mapper.getAllUser().forEach(user -> System.out.println(user));}*/@Autowiredprivate UserMapper userMapper;/*---------------------------------使用MyBatisPlus之后-------------------------------------*/@Testpublic void testMyBatisPlus(){//查詢所有用戶信息// SELECT id,name,age,email FROM userSystem.out.println(userMapper.selectList(null));}2.5.3 結(jié)果
2.6 總結(jié)
在Spring整合MyBatis中加入了MyBatis-Plus后,我們就可以使用MyBatis-Plus所提供的BaseMapper實(shí)現(xiàn)CRUD,并不需要編寫映射文件以及SQL語句
但是若要自定義SQL語句,仍然可以編寫映射文件而不造成任何影響。因?yàn)镸yBatis-Plus只做增強(qiáng),而不做改變。
三、基本CRUD
3.1 BaseMapper
MyBatis-Plus中的基本CRUD在內(nèi)置的BaseMapper中都已得到了實(shí)現(xiàn),我們可以直接使用,接口如下:
/*** Mapper 繼承該接口后,無需編寫 mapper.xml 文件,即可獲得CRUD功能* <p>這個(gè) Mapper 支持 id 泛型</p>** @author hubin* @since 2016-01-23*/ public interface BaseMapper<T> extends Mapper<T> {/*** 插入一條記錄** @param entity 實(shí)體對(duì)象*/int insert(T entity);/*** 根據(jù) ID 刪除** @param id 主鍵ID*/int deleteById(Serializable id);/*** 根據(jù)實(shí)體(ID)刪除** @param entity 實(shí)體對(duì)象* @since 3.4.4*/int deleteById(T entity);/*** 根據(jù) columnMap 條件,刪除記錄** @param columnMap 表字段 map 對(duì)象*/int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根據(jù) entity 條件,刪除記錄** @param queryWrapper 實(shí)體對(duì)象封裝操作類(可以為 null,里面的 entity 用于生成 where 語句)*/int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 刪除(根據(jù)ID 批量刪除)** @param idList 主鍵ID列表(不能為 null 以及 empty)*/int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 根據(jù) ID 修改** @param entity 實(shí)體對(duì)象*/int updateById(@Param(Constants.ENTITY) T entity);/*** 根據(jù) whereEntity 條件,更新記錄** @param entity 實(shí)體對(duì)象 (set 條件值,可以為 null)* @param updateWrapper 實(shí)體對(duì)象封裝操作類(可以為 null,里面的 entity 用于生成 where 語句)*/int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);/*** 根據(jù) ID 查詢** @param id 主鍵ID*/T selectById(Serializable id);/*** 查詢(根據(jù)ID 批量查詢)** @param idList 主鍵ID列表(不能為 null 以及 empty)*/List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 查詢(根據(jù) columnMap 條件)** @param columnMap 表字段 map 對(duì)象*/List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根據(jù) entity 條件,查詢一條記錄* <p>查詢一條記錄,例如 qw.last("limit 1") 限制取一條記錄, 注意:多條數(shù)據(jù)會(huì)報(bào)異常</p>** @param queryWrapper 實(shí)體對(duì)象封裝操作類(可以為 null)*/default T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {List<T> ts = this.selectList(queryWrapper);if (CollectionUtils.isNotEmpty(ts)) {if (ts.size() != 1) {throw ExceptionUtils.mpe("One record is expected, but the query result is multiple records");}return ts.get(0);}return null;}/*** 根據(jù) Wrapper 條件,查詢總記錄數(shù)** @param queryWrapper 實(shí)體對(duì)象封裝操作類(可以為 null)*/Long selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據(jù) entity 條件,查詢?nèi)坑涗?* @param queryWrapper 實(shí)體對(duì)象封裝操作類(可以為 null)*/List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據(jù) Wrapper 條件,查詢?nèi)坑涗?* @param queryWrapper 實(shí)體對(duì)象封裝操作類(可以為 null)*/List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據(jù) Wrapper 條件,查詢?nèi)坑涗? <p>注意: 只返回第一個(gè)字段的值</p>** @param queryWrapper 實(shí)體對(duì)象封裝操作類(可以為 null)*/List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據(jù) entity 條件,查詢?nèi)坑涗?#xff08;并翻頁)** @param page 分頁查詢條件(可以為 RowBounds.DEFAULT)* @param queryWrapper 實(shí)體對(duì)象封裝操作類(可以為 null)*/<P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據(jù) Wrapper 條件,查詢?nèi)坑涗?#xff08;并翻頁)** @param page 分頁查詢條件* @param queryWrapper 實(shí)體對(duì)象封裝操作類*/<P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); }3.2 BaseMapper功能測(cè)試
//插入@Testpublic void testInsert(){// INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )User user = new User(6,"張三",23,"zhangsan@126.com");int result = userMapper.insert(user);System.out.println("result="+result);}//刪除@Testpublic void testDelete(){//根據(jù)Id刪除用戶//DELETE FROM user WHERE id=?int result = userMapper.deleteById(2L);//根據(jù)map集合刪除//DELETE FROM user WHERE name = ? AND age = ?Map<String,Object> map = new HashMap<>();map.put("name","張三");map.put("age",23);int result = userMapper.deleteByMap(map);// 根據(jù)id批量刪除// DELETE FROM user WHERE id IN ( ? , ? , ? )List<Integer> list = Arrays.asList(1, 2, 3);int result = userMapper.deleteBatchIds(list);System.out.println("result="+result);}//修改@Testpublic void testUpdate(){ // UPDATE user SET name=?, email=? WHERE id=?User user = new User();user.setId(4L);user.setName("李四");user.setEmail("lisi@atguigu.com");int result = userMapper.updateById(user);System.out.println("result="+result);}//查詢@Testpublic void testSelect(){//根據(jù)Id查詢用戶 // SELECT id,name,age,email FROM user WHERE id=?User user = userMapper.selectById(5L);System.out.println(user);// SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )List<Integer> list = Arrays.asList(1, 2, 4);List<User> users = userMapper.selectBatchIds(list);users.forEach(System.out::println);Map<String,Object> map = new HashMap<>();map.put("age",23);List<User> users = userMapper.selectByMap(map);users.forEach(System.out::println);}通過觀察BaseMapper中的方法,大多方法中都有Wrapper類型的形參,此為條件構(gòu)造器,可針對(duì)于SQL語句設(shè)置不同的條件,若沒有條件,則可以為該形參賦值null,即查詢(刪除/修改)所有數(shù)據(jù)
3.3 通用Service
說明:
- 通用 Service CRUD 封裝IService接口,進(jìn)一步封裝 CRUD 采用 get 查詢單行 remove 刪除 list 查詢集合 page 分頁 , 前綴命名方式區(qū)分 Mapper 層避免混淆
- 泛型 T 為任意實(shí)體對(duì)象
- 建議如果存在自定義通用 Service 方法的可能,請(qǐng)創(chuàng)建自己的 IBaseService 繼承Mybatis-Plus 提供的基類
- 官網(wǎng)地址:https://baomidou.com/pages/49cc81/#service-crud-%E6%8E%A5%E5%8F%A3
3.3.1 IService
MyBatis-Plus中有一個(gè)接口 IService和其實(shí)現(xiàn)類 ServiceImpl,封裝了常見的業(yè)務(wù)層邏輯
詳情查看源碼IService和ServiceImpl
3.3.2 創(chuàng)建Service接口和實(shí)現(xiàn)類
UserService
/** * UserService繼承IService模板提供的基礎(chǔ)功能 */ public interface UserService extends IService<User> {}UserServiceImpl
/** * ServiceImpl實(shí)現(xiàn)了IService,提供了IService中基礎(chǔ)功能的實(shí)現(xiàn) * 若ServiceImpl無法滿足業(yè)務(wù)需求,則可以使用自定的UserService定義方法,并在實(shí)現(xiàn)類中實(shí)現(xiàn) */ @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}3.3.3 在spring配置文件中設(shè)置自動(dòng)掃描service的包
在applicationContext.xml中添加掃描組件的配置,掃描業(yè)務(wù)層組件,用于測(cè)試
<context:component-scan base-package="com.atguigu.mybatisplus.service.impl"></context:component-scan>3.3.4 測(cè)試查詢記錄條數(shù)和批量添加
//spring測(cè)試類寫法一 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisServiceTest {@Autowiredprivate UserService userService;@Testpublic void testCount(){//查詢總記錄條數(shù)//SELECT COUNT( * ) FROM userlong count = userService.count();System.out.println("總記錄條數(shù)" + count);}@Testpublic void testSaveBatch(){//實(shí)現(xiàn)新增用戶ArrayList<User> list = new ArrayList<>();// SQL長(zhǎng)度有限制,海量數(shù)據(jù)插入單條SQL無法實(shí)行,// 因此MP將批量插入放在了通用Service中實(shí)現(xiàn),而不是通用Mapperfor (int i = 0; i < 100 ; i++) {User user = new User();user.setName("abc"+i);user.setAge(20+i);list.add(user);}//INSERT INTO user ( id, name, age ) VALUES ( ?, ?, ? )boolean b = userService.saveBatch(list);System.out.println(b);}}錯(cuò)誤:
Duplicate entry ‘0’ for key ‘PRIMARY’
原因:發(fā)現(xiàn)了是數(shù)據(jù)庫(kù)表設(shè)計(jì)不合理導(dǎo)致的;
因?yàn)橹麈I設(shè)置不能為空,因此默認(rèn)是以"0"來進(jìn)行填充的。因此在數(shù)據(jù)插入時(shí)數(shù)據(jù)的主鍵id值被0占據(jù),但由于之前已經(jīng)有數(shù)據(jù)了,id為“0”的索引已經(jīng)被占,在使用就會(huì)報(bào)這個(gè)錯(cuò)誤,因此我們只需要對(duì)表中的主鍵“id”設(shè)置成自增即可。
糾正:為什么會(huì)出現(xiàn)這個(gè)問題,是因?yàn)樵趧?chuàng)建實(shí)體類的時(shí)候id屬性的類型寫成long了,應(yīng)該寫成Long,不然雪花算法是不會(huì)實(shí)現(xiàn)的。大小寫要注意。
四、常用注解
4.1 @TableName
經(jīng)過以上的測(cè)試,在使用MyBatis-Plus實(shí)現(xiàn)基本的CRUD時(shí),我們并沒有指定要操作的表,只是在Mapper接口繼承BaseMapper時(shí),設(shè)置了泛型User,而操作的表為user表:
由此得出結(jié)論,MyBatis-Plus在確定操作的表時(shí),由BaseMapper的泛型決定,即實(shí)體類型決定,且默認(rèn)操作的表名和實(shí)體類型的類名一致
4.1.1 問題
若實(shí)體類類型的類名和要操作的表的表名不一致,會(huì)出現(xiàn)什么問題?
我們將表user更名為t_user,測(cè)試查詢功能
程序拋出異常,Table ‘mybatis_plus.user’ doesn’t exist,因?yàn)楝F(xiàn)在的表名為t_user,而默認(rèn)操作的表名和實(shí)體類型的類名一致,即user表
4.1.2 通過@TableName解決問題
在實(shí)體類類型上添加==@TableName(“t_user”)==,標(biāo)識(shí)實(shí)體類對(duì)應(yīng)的表,即可成功執(zhí)行SQL語句。
4.1.3 通過GlobalConfig解決問題
在開發(fā)的過程中,我們經(jīng)常遇到以上的問題,即實(shí)體類所對(duì)應(yīng)的表都有固定的前綴,例如t_或tbl_
此時(shí),可以使用MyBatis-Plus提供的全局配置,為實(shí)體類所對(duì)應(yīng)的表名設(shè)置默認(rèn)的前綴,那么就不需要在每個(gè)實(shí)體類上通過@TableName標(biāo)識(shí)實(shí)體類對(duì)應(yīng)的表。
在spring配置文件中修改:spring-persist.xml中的sqlsessionfactorybean
<!--使用mybatisplus--><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!--指定mybatis配置文件--><property name="configLocation" value="classpath:mybatis-config.xml"/><!--指定mapper.xml--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/><!--裝配數(shù)據(jù)源--><property name="dataSource" ref="dataSource"/><!--設(shè)置mybatisplus的全局配置,即表的前綴--><property name="globalConfig" ref="globalConfig"></property></bean><bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig"><property name="dbConfig"><bean id="config" class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig"><!--設(shè)置實(shí)體類所對(duì)應(yīng)的表的前綴--><property name="tablePrefix" value="t_"></property></bean></property></bean>4.2 @TableId
經(jīng)過以上的測(cè)試,MyBatis-Plus在實(shí)現(xiàn)CRUD時(shí),會(huì)默認(rèn)將id作為主鍵列,并在插入數(shù)據(jù)時(shí),默認(rèn)基于雪花算法的策略生成id。
4.2.1 問題引出
若實(shí)體類和表中表示主鍵的不是id,而是其他字段,例如uid,MyBatis-Plus會(huì)自動(dòng)識(shí)別uid為主鍵列嗎?
我們實(shí)體類中的屬性id改為uid,將表中的字段id也改為uid,測(cè)試添加功能程序拋出異常,Field ‘uid’ doesn’t have a default value,說明MyBatis-Plus沒有將uid作為主鍵賦值
4.2.2 通過@TableId解決問題
在實(shí)體類中uid屬性上通過@TableId將其標(biāo)識(shí)為主鍵,即可成功執(zhí)行SQL語句。
4.2.3 @TableId的value屬性
若實(shí)體類中主鍵對(duì)應(yīng)的屬性為id,而表中表示主鍵的字段為uid,此時(shí)若只在屬性id上添加注解@TableId,則拋出異常Unknown column ‘id’ in ‘field list’,即MyBatis-Plus仍然會(huì)將id作為表的主鍵操作,而表中表示主鍵的是字段uid
此時(shí)需要通過@TableId注解的value屬性,指定表中的主鍵字段@TableId(“uid”)或@TableId(value=“uid”)
4.2.4 @TableId的type屬性
type屬性用來定義主鍵策略
[1]臨時(shí)修改
[2] 配置全局配置(全局有效)
在spring-persist.xml中修改。
4.2.5 雪花算法
4.3 @TableField
經(jīng)過以上的測(cè)試,我們可以發(fā)現(xiàn),MyBatis-Plus在執(zhí)行SQL語句時(shí),要保證實(shí)體類中的屬性名和表中的字段名一致
如果實(shí)體類中的屬性名和字段名不一致的情況,會(huì)出現(xiàn)什么問題呢?
a>情況1
若實(shí)體類中的屬性使用的是駝峰命名風(fēng)格,而表中的字段使用的是下劃線命名風(fēng)格
例如實(shí)體類屬性u(píng)serName,表中字段user_name
此時(shí)MyBatis-Plus會(huì)自動(dòng)將下劃線命名風(fēng)格轉(zhuǎn)化為駝峰命名風(fēng)格
相當(dāng)于在MyBatis中配置
b>情況2
若實(shí)體類中的屬性和表中的字段不滿足情況1
例如實(shí)體類屬性name,表中字段username
此時(shí)需要在實(shí)體類屬性上使用@TableField(“username”)設(shè)置屬性所對(duì)應(yīng)的字段名
4.4 @TableLogic(邏輯刪除)
4.4.1 邏輯刪除
邏輯刪除
物理刪除:真實(shí)刪除,將對(duì)應(yīng)數(shù)據(jù)從數(shù)據(jù)庫(kù)中刪除,之后查詢不到此條被刪除的數(shù)據(jù)
邏輯刪除:假刪除,將對(duì)應(yīng)數(shù)據(jù)中代表是否被刪除字段的狀態(tài)修改為“被刪除狀態(tài)”,之后在數(shù)據(jù)庫(kù)中仍舊能看到此條數(shù)據(jù)記錄
使用場(chǎng)景:可以進(jìn)行數(shù)據(jù)恢復(fù)
4.4.2 實(shí)現(xiàn)邏輯刪除
數(shù)據(jù)庫(kù)中創(chuàng)建邏輯刪除狀態(tài)列,設(shè)置默認(rèn)值為0
實(shí)體類中添加邏輯刪除屬性
- 測(cè)試刪除功能,真正執(zhí)行的是修改
UPDATE t_user SET is_deleted=1 WHERE id=? AND is_deleted=0 - 測(cè)試查詢功能,被邏輯刪除的數(shù)據(jù)默認(rèn)不會(huì)被查詢
SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0
五、條件構(gòu)造器和常用接口
5.1 wapper介紹
5.2 QueryWrapper
5.2.1 組裝查詢條件
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisPlusWrapperTest {@Autowiredpublic UserMapper userMapper;@Testpublic void test01(){//查詢用戶名包含a,年齡在20到30之間,并且郵箱不為null的用戶信息QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)queryWrapper.like("user_name","a").between("age",20,30).isNotNull("email");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}5.2.2 組裝排序條件
@Testpublic void test02(){//按年齡降序查詢用戶,如果年齡相同則按id升序排列//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASCQueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByDesc("age").orderByAsc("uid");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}5.2.3 組裝刪除條件
@Testpublic void test03(){//刪除email為空的用戶QueryWrapper<User> queryWrapper = new QueryWrapper<>();//UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)//出現(xiàn)這個(gè)是因?yàn)槲覀冊(cè)O(shè)置了邏輯刪除,即刪除變成了修改,將狀態(tài)從0(未刪除狀態(tài))--->1(已刪除狀態(tài));queryWrapper.isNull("email");int result = userMapper.delete(queryWrapper);System.out.println("受影響的行數(shù) : " + result);}5.2.4 條件的優(yōu)先級(jí)
/*** update(User entity,Wrapper<User> updateWrapper)* 第一個(gè)參數(shù)為修改的內(nèi)容,第二個(gè)參數(shù)為設(shè)置修改的條件參數(shù)1設(shè)置修改的字段和值,參數(shù)2是查詢符合的條件**/@Testpublic void test04(){//條件包裝器中條件之間默認(rèn)是and連接。我們不需要手動(dòng)設(shè)置,但是如果是或,我們需要手動(dòng)設(shè)置or.//將(年齡大于20并且用戶名中包含有a)或郵箱為null的用戶信息修改QueryWrapper<User> queryWrapper = new QueryWrapper<>();//UPDATE t_user SET user_name=?, age=?, email=? WHERE is_deleted=0 AND (user_name LIKE ? AND age > ? OR email IS NULL)queryWrapper.like("user_name","a").gt("age",20).or().isNull("email");User user = new User();user.setName("小明");user.setEmail("test@atguigu.com");int result = userMapper.update(user, queryWrapper);System.out.println("受影響的行數(shù):" + result);} @Testpublic void test05(){//將(年齡大于20或郵箱為null)并且用戶名中包含有a的用戶信息修改//lambda表達(dá)式內(nèi)的邏輯優(yōu)先運(yùn)算QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))queryWrapper.like("user_name","a").and(i ->i.gt("age",20).or().isNull("email"));List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}5.2.5 組裝select子句
@Testpublic void test06(){//查詢用戶信息的username和age字段QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT user_name,age FROM t_user WHERE is_deleted=0queryWrapper.select("user_name","age");List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);maps.forEach(System.out::println);}5.2.6 實(shí)現(xiàn)子查詢
@Testpublic void test07(){//查詢id小于等于3的用戶信息QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (uid IN (select uid from t_user where uid <= 3))queryWrapper.inSql("uid","select uid from t_user where uid <= 3");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}5.3 UpdateWrapper
@Testpublic void test08(){//將用戶名中包含有a并且(年齡大于20或郵箱為null)的用戶信息修改// 組裝set子句以及修改條件UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();/*寫在一起updateWrapper.set("age",18).set("email","user@atguigu.com").like("user_name","a").and(i ->i.gt("age",20).or().isNull("email"));*///分開寫//UPDATE t_user SET user_name=?,email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))updateWrapper.like("user_name","a").and(i ->i.gt("age",20).or().isNull("email"));updateWrapper.set("user_name","小黑").set("email","abc@atguigu.xom");//這里必須要?jiǎng)?chuàng)建User對(duì)象,否則無法應(yīng)用自動(dòng)填充。如果沒有自動(dòng)填充,可以設(shè)置為null//UPDATE t_user SET username=?, age=?,email=? WHERE (username LIKE ? AND(age > ? OR email IS NULL))//User user = new User();//user.setName("張三");//int result = userMapper.update(user, updateWrapper);//UPDATE t_user SET age=?,email=? WHERE (username LIKE ? AND (age > ? ORemail IS NULL))int result = userMapper.update(null, updateWrapper);System.out.println("result = " + result);}5.4 condition
在真正開發(fā)的過程中,組裝條件是常見的功能,而這些條件數(shù)據(jù)來源于用戶輸入,是可選的,因此我們?cè)诮M裝這些條件時(shí),必須先判斷用戶是否選擇了這些條件,若選擇則需要組裝該條件,若沒有選擇則一定不能組裝,以免影響SQL執(zhí)行的結(jié)果。
思路一:
@Testpublic void test09(){//定義查詢條件,有可能為null(用戶未輸入或未選擇)String username = null;Integer ageBegin = 20;Integer ageEnd = 30;QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (age >= ? AND age <= ?)//StringUtils.isNotBlank()判斷某字符串是否不為空且長(zhǎng)度不為0且不由空白符(whitespace)構(gòu)成if(StringUtils.isNotBlank(username)){queryWrapper.like("user_name","a");}if (ageBegin != null){queryWrapper.ge("age",ageBegin);}if (ageEnd != null){queryWrapper.le("age",ageEnd);}List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}思路2:
上面的實(shí)現(xiàn)方案沒有問題,但是代碼比較復(fù)雜,我們可以使用帶condition參數(shù)的重載方法構(gòu)建查詢條件,簡(jiǎn)化代碼的編寫
@Testpublic void test10(){String username = "a";Integer ageBegin = null;Integer ageEnd = 30;QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age <= ?)queryWrapper.like(StringUtils.isNotBlank(username),"user_name","a").ge(ageBegin != null,"age",ageBegin).le(ageEnd != null,"age",ageEnd);List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}5.5 LambdaQueryWrapper
@Testpublic void test11(){String username = "a";Integer ageBegin = null;Integer ageEnd = 30;LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age <= ?)queryWrapper.like(StringUtils.isNotBlank(username),User::getName,"a").ge(ageBegin != null,User::getAge,ageBegin).le(ageEnd != null,User::getAge,ageEnd);List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}5.6 LambdaUpdateWrapper
@Testpublic void test12(){//將用戶名中包含有a并且(年齡大于20或郵箱為null)的用戶信息修改// 組裝set子句以及修改條件LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();/*合在一起updateWrapper.set(User::getAge, 18).set(User::getEmail, "user@atguigu.com").like(User::getName, "a").and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail));*///分開寫updateWrapper.like(User::getName, "a").and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail));updateWrapper.set(User::getName,"小黑").set(User::getEmail,"abc@atguigu.com");User user = new User();int result = userMapper.update(user, updateWrapper);System.out.println("受影響的行數(shù):" + result);}六、插件
6.1 分頁插件
MyBatis Plus自帶分頁插件,只要簡(jiǎn)單的配置即可實(shí)現(xiàn)分頁功能。
6.1.1 添加配置
<!--使用mybatisplus--><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!--指定mybatis配置文件--><property name="configLocation" value="classpath:mybatis-config.xml"/><!--指定mapper.xml--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/><!--裝配數(shù)據(jù)源--><property name="dataSource" ref="dataSource"/><!--設(shè)置mybatisplus的全局配置,即表的前綴--><property name="globalConfig" ref="globalConfig"></property><!--配置插件--><property name="plugins"><array><ref bean="mybatisPlusInterceptor"></ref></array></property></bean><!--配置MyBatis-Plus插件--><bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"><property name="interceptors"><list><ref bean="paginationInnerInterceptor"></ref></list></property></bean><!--配置Mybatis-plus分頁插件的bean--><bean id="paginationInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor"><!--設(shè)置數(shù)據(jù)庫(kù)類型--><property name="dbType" value="MYSQL"></property></bean>6.1.2 測(cè)試
@Testpublic void testPage(){//設(shè)置分頁參數(shù)Page<User> page = new Page<>(2,3);userMapper.selectPage(page,null);List<User> list = page.getRecords();list.forEach(System.out::println);System.out.println("每頁顯示的條數(shù):"+page.getSize());System.out.println("總記錄數(shù):"+page.getTotal());System.out.println("總頁數(shù):"+page.getPages());System.out.println( "當(dāng)前頁:" + page.getCurrent());System.out.println("是否有下一頁:" + page.hasNext());System.out.println("是否有上一頁:" + page.hasPrevious());}測(cè)試結(jié)果:
User(id=1, name=Jone, age=18, email=test1@baomidou.com, isDeleted=0) User(id=2,name=Jack, age=20, email=test2@baomidou.com, isDeleted=0) User(id=3, name=Tom,age=28, email=test3@baomidou.com, isDeleted=0) User(id=4, name=Sandy, age=21,email=test4@baomidou.com, isDeleted=0) User(id=5, name=Billie, age=24, email=test5@baomidou.com, isDeleted=0) 當(dāng)前頁:1 每頁顯示的條數(shù):5 總記錄數(shù):17 總頁數(shù):4 是否有上一
頁:false 是否有下一頁:true
6.2 xml自定義分頁
6.2.1 UserMapper中定義接口方法
/*** 根據(jù)年齡查詢用戶列表,分頁顯示* @param page 分頁對(duì)象,xml中可以從里面進(jìn)行取值,傳遞參數(shù) Page 即自動(dòng)分頁,必須放在第一位* @param age 年齡* @return*/IPage<User> selectPageVo(@Param("page") Page<User> page , @Param("age") Integer age);}6.2.2 UserMapper.xml中編寫SQL
<!--IPage<User> selectPageVo(@Param("page") Page<User> page , @Param("age") Integer age);--><select id="selectPageVo" resultType="User">select uid,user_name,age,email from t_user where age > #{age}</select>6.2.3 測(cè)試
@Testpublic void testPageVo(){Page<User> page = new Page<>(1,5);//第一頁索引為1,不是0userMapper.selectPageVo(page,20);List<User> list = page.getRecords();list.forEach(System.out::println);System.out.println("每頁顯示的條數(shù):"+page.getSize());System.out.println("總記錄數(shù):"+page.getTotal());System.out.println("總頁數(shù):"+page.getPages());System.out.println( "當(dāng)前頁:" + page.getCurrent());System.out.println("是否有下一頁:" + page.hasNext());System.out.println("是否有上一頁:" + page.hasPrevious());}結(jié)果:
User(id=3, name=Tom, age=28, email=test3@baomidou.com, isDeleted=null)
User(id=4,name=Sandy, age=21,email=test4@baomidou.com, isDeleted=null) User(id=5, name=Billie,age=24, email=test5@baomidou.com, isDeleted=null) User(id=8,name=ybc1, age=21,email=null, isDeleted=null)
User(id=9, name=ybc2, age=22,email=null, isDeleted=null)
當(dāng)前頁:1 每頁顯示的條數(shù):5 總記錄數(shù):12 總頁數(shù):3 是否有上一頁:false 是否有下一頁:true
6.3 樂觀鎖
6.3.1 場(chǎng)景
一件商品,成本價(jià)是80元,售價(jià)是100元。老板先是通知小李,說你去把商品價(jià)格增加50元。小李正在玩游戲,耽擱了一個(gè)小時(shí)。正好一個(gè)小時(shí)后,老板覺得商品價(jià)格增加到150元,價(jià)格太高,可能會(huì)影響銷量。又通知小王,你把商品價(jià)格降低30元。
此時(shí),小李和小王同時(shí)操作商品后臺(tái)系統(tǒng)。小李操作的時(shí)候,系統(tǒng)先取出商品價(jià)格100元;小王也在操作,取出的商品價(jià)格也是100元。小李將價(jià)格加了50元,并將100+50=150元存入了數(shù)據(jù)
庫(kù);小王將商品減了30元,并將100-30=70元存入了數(shù)據(jù)庫(kù)。是的,如果沒有鎖,小李的操作就完全被小王的覆蓋了。
現(xiàn)在商品價(jià)格是70元,比成本價(jià)低10元。幾分鐘后,這個(gè)商品很快出售了1千多件商品,老板虧1萬多。
6.3.2 樂觀鎖與悲觀鎖
上面的故事,如果是樂觀鎖,小王保存價(jià)格前,會(huì)檢查下價(jià)格是否被人修改過了。如果被修改過了,則重新取出的被修改后的價(jià)格,150元,這樣他會(huì)將120元存入數(shù)據(jù)庫(kù)。
如果是悲觀鎖,小李取出數(shù)據(jù)后,小王只能等小李操作完之后,才能對(duì)價(jià)格進(jìn)行操作,也會(huì)保證最終的價(jià)格是120元。
6.3.3 模擬修改沖突
a>數(shù)據(jù)庫(kù)中增加商品表
CREATE TABLE t_product ( id BIGINT(20) NOT NULL COMMENT '主鍵ID', NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名稱', price INT(11) DEFAULT 0 COMMENT '價(jià)格', VERSION INT(11) DEFAULT 0 COMMENT '樂觀鎖版本號(hào)', PRIMARY KEY (id) );b>添加數(shù)據(jù)
INSERT INTO t_product (id, NAME, price) VALUES (1, '外星人筆記本', 100);c>添加實(shí)體
*/@Data public class Product {private Long id;private String name;private Integer price;}d>添加mapper
public interface ProductMapper extends BaseMapper<Product> {}f>測(cè)試
@Testpublic void testProduct01(){//小李查詢價(jià)格Product productLi = productMapper.selectById(1);System.out.println("小李查詢的商品價(jià)格:" + productLi.getPrice());//小王查詢價(jià)格Product productWang = productMapper.selectById(1);System.out.println("小王查詢的商品價(jià)格:" + productWang.getPrice());//小李將商品價(jià)格+50productLi.setPrice(productLi.getPrice() + 50);productMapper.updateById(productLi);//小王將商品價(jià)格-30productWang.setPrice(productWang.getPrice() - 30);int result = productMapper.updateById(productWang);//老板查詢商品價(jià)格Product productBoss = productMapper.selectById(1);System.out.println("老板查詢的商品價(jià)格為:" + productBoss.getPrice());}6.3.4 樂觀鎖實(shí)現(xiàn)流程
數(shù)據(jù)庫(kù)中添加version字段
取出記錄時(shí),獲取當(dāng)前version
更新時(shí),version + 1,如果where語句中的version版本不對(duì),則更新失敗
UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=16.3.5 Mybatis-Plus實(shí)現(xiàn)樂觀鎖
[1]修改實(shí)體類
*/@Data public class Product {private Long id;private String name;private Integer price;@Versionprivate Integer version;}[2]添加樂觀鎖插件配置
<!--配置MyBatis-Plus插件--><bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"><property name="interceptors"><list><ref bean="paginationInnerInterceptor"></ref><ref bean="optimisticLockerInnerInterceptor"></ref></list></property></bean><!--配置樂觀鎖插件--><bean id="optimisticLockerInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor"></bean>[3] 測(cè)試修改沖突
小李查詢商品信息:
SELECT id,name,price,version FROM t_product WHERE id=?
小王查詢商品信息:
SELECT id,name,price,version FROM t_product WHERE id=?
小李修改商品價(jià)格,自動(dòng)將version+1
UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
Parameters: 外星人筆記本(String), 150(Integer), 1(Integer), 1(Long), 0(Integer)
小王修改商品價(jià)格,此時(shí)version已更新,條件不成立,修改失敗
UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
Parameters: 外星人筆記本(String), 70(Integer), 1(Integer), 1(Long), 0(Integer)
最終,小王修改失敗,查詢價(jià)格:150
SELECT id,name,price,version FROM t_product WHERE id=?
[4]優(yōu)化流程
@Testpublic void testProduct01(){//小李查詢價(jià)格Product productLi = productMapper.selectById(1);System.out.println("小李查詢的商品價(jià)格:" + productLi.getPrice());//小王查詢價(jià)格Product productWang = productMapper.selectById(1);System.out.println("小王查詢的商品價(jià)格:" + productWang.getPrice());//小李將商品價(jià)格+50productLi.setPrice(productLi.getPrice() + 50);productMapper.updateById(productLi);//小王將商品價(jià)格-30productWang.setPrice(productWang.getPrice() - 30);int result = productMapper.updateById(productWang);if (result == 0){//操作失敗,重試Product productNew = productMapper.selectById(1);productNew.setPrice(productNew.getPrice() - 30);productMapper.updateById(productNew);}//老板查詢商品價(jià)格Product productBoss = productMapper.selectById(1);System.out.println("老板查詢的商品價(jià)格為:" + productBoss.getPrice());}七 、通用枚舉
表中的有些字段值是固定的,例如性別(男或女),此時(shí)我們可以使用MyBatis-Plus的通用枚舉來實(shí)現(xiàn)。
7.1 數(shù)據(jù)庫(kù)添加字段sex
7.2 創(chuàng)建通用枚舉
*/@Getter public enum SexEnum {MALE(1,"男"),FEMALE(2,"女");@EnumValue //將注解所標(biāo)識(shí)的屬性的值存儲(chǔ)到數(shù)據(jù)庫(kù)中private Integer sex;private String sexName;SexEnum(Integer sex, String sexName) {this.sex = sex;this.sexName = sexName;} }7.3 配置掃描通用枚舉
<!--使用mybatisplus--><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!--指定mybatis配置文件--><property name="configLocation" value="classpath:mybatis-config.xml"/><!--指定mapper.xml--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/><!--裝配數(shù)據(jù)源--><property name="dataSource" ref="dataSource"/><!--設(shè)置mybatisplus的全局配置,即表的前綴--><property name="globalConfig" ref="globalConfig"></property><!--配置掃描通用枚舉--><property name="typeEnumsPackage" value="com.atguigu.mybatisplus.enums"></property><!--配置插件--><property name="plugins"><array><ref bean="mybatisPlusInterceptor"></ref></array></property></bean>7.4 測(cè)試
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisPlusEnumTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSexEnum(){User user = new User();user.setName("Enum");user.setAge(20);//設(shè)置性別信息為枚舉項(xiàng),會(huì)將@EnumValue注解所標(biāo)識(shí)的屬性值存儲(chǔ)到數(shù)據(jù)庫(kù)// INSERT INTO t_user ( user_name, age, sex, is_deleted ) VALUES ( ?, ?, ?, ? )user.setSex(SexEnum.MALE);userMapper.insert(user);}八、代碼生成器
8.1 引入依賴
<!--代碼生成器逆向工程依賴--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><!--代碼生成器中 freemarker引擎模板需要這個(gè)依賴--><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency>8.2 快速生成
public class FastAutoGeneratorTest {public static void main(String[] args) {FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false","root", "5864@WCY").globalConfig(builder -> {builder.author("atguigu") // 設(shè)置作者// .enableSwagger() // 開啟 swagger 模式.fileOverride() // 覆蓋已生成文件.outputDir("F://JAVA listen//code//mybatis_plus"); // 指定輸出目錄}).packageConfig(builder -> {builder.parent("com.atguigu") // 設(shè)置父包名.moduleName("mybatisplus") // 設(shè)置父包模塊名.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "F://JAVA listen//code//mybatis_plus"));// 設(shè)置mapperXml生成路徑}).strategyConfig(builder -> {builder.addInclude("t_user") // 設(shè)置需要生成的表名.addTablePrefix("t_", "c_"); // 設(shè)置過濾表前綴}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker 引擎模板,默認(rèn)的是Velocity引擎模板.execute();}}九 、MyBatisX插件
MyBatis-Plus為我們提供了強(qiáng)大的mapper和service模板,能夠大大的提高開發(fā)效率。
但是在真正開發(fā)過程中,MyBatis-Plus并不能為我們解決所有問題,例如一些復(fù)雜的SQL,多表聯(lián)查,我們就需要自己去編寫代碼和SQL語句,我們?cè)撊绾慰焖俚慕鉀Q這個(gè)問題呢,這個(gè)時(shí)候可以使用MyBatisX插件。
MyBatisX一款基于 IDEA 的快速開發(fā)插件,為效率而生。
MyBatisX插件用法:https://baomidou.com/pages/ba5b24/
9.1 安裝插件
安裝方法:打開 IDEA,進(jìn)入 File -> Settings -> Plugins -> Browse Repositories,輸入 mybatisx 搜索并安裝
9.2 功能
9.2.1 XML跳轉(zhuǎn)
當(dāng)mapper映射文件和mapper很多的時(shí)候,可以快速定位并跳轉(zhuǎn)到對(duì)應(yīng)的類容上。
9.2.2 快速生成代碼
[1]首先需要在datasource中進(jìn)行配置
[2] 選擇驅(qū)動(dòng)
[3]可以直接選擇舊版本的驅(qū)動(dòng),或者按提示下載
[4] 登錄后選擇數(shù)據(jù)庫(kù)、表,然后點(diǎn)擊右鍵選擇mybatisx。
[5] 表的基本配置
[6] 生成的基本配置
[7]選擇好后會(huì)自動(dòng)幫我們生成各種組件
[8]如果我們要自定義查詢功能,我們只需要在mapper中寫我們的方法名,插件會(huì)自動(dòng)幫助我們補(bǔ)全方法名并且快速生成相對(duì)應(yīng)的sql語句放在mapper映射文件中。
十、總結(jié)
mybatsi-plus可以快速幫助我們完成spring和mybatsi的整合及搭建功能。
總結(jié)
以上是生活随笔為你收集整理的MyBatis_Plus(Spring版本笔记)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Docker从入门到放弃------do
- 下一篇: 如何讲解一个C语言程序,解读第一个C++