wordpress國(guó)外主題慢點(diǎn)擊排名優(yōu)化
目錄
簡(jiǎn)介
安裝
Spring Boot2
Spring Boot3
Spring
配置
Spring Boot 工程
Spring 工程
常見注解
條件構(gòu)造器
流式查詢
使用示例
批量操作
使用示例
自定義SQL
Service接口
CRUD
擴(kuò)展功能
代碼生成
安裝插件
通用枚舉
配置枚舉處理器
插件功能
配置示例
簡(jiǎn)介
MyBatis-Plus 是一個(gè) MyBatis 的增強(qiáng)工具,在 MyBatis 的基礎(chǔ)上只做增強(qiáng)不做改變,為簡(jiǎn)化開發(fā)、提高效率而生。?
特性
- 無侵入:只做增強(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)置分頁(yè)插件:基于 MyBatis 物理分頁(yè),開發(fā)者無需關(guān)心具體操作,配置好插件之后,寫分頁(yè)等同于普通 List 查詢
- 分頁(yè)插件支持多種數(shù)據(jù)庫(kù):支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多種數(shù)據(jù)庫(kù)
- 內(nèi)置性能分析插件:可輸出 SQL 語(yǔ)句以及其執(zhí)行時(shí)間,建議開發(fā)測(cè)試時(shí)啟用該功能,能快速揪出慢查詢
- 內(nèi)置全局?jǐn)r截插件:提供全表 delete 、 update 操作智能分析阻斷,也可自定義攔截規(guī)則,預(yù)防誤操作
安裝
Spring Boot2
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.7</version>
</dependency>
Spring Boot3
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.7</version>
</dependency>
Spring
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>3.5.7</version>
</dependency>
注意事項(xiàng)
????????引入 MyBatis-Plus 之后請(qǐng)不要再次引入 MyBatis 以及 mybatis-spring-boot-starter和MyBatis-Spring,以避免因版本差異導(dǎo)致的問題。
????????自3.5.4開始,在沒有使用mybatis-plus-boot-starter或mybatis-plus-spring-boot3-starter情況下,請(qǐng)自行根據(jù)項(xiàng)目情況引入mybatis-spring。
配置
Spring Boot 工程
配置 MapperScan 注解
@SpringBootApplication
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
大多數(shù)的配置都有默認(rèn)值,因此我們都無需配置。但還有一些是沒有默認(rèn)值的,例如:
1、實(shí)體類的別名掃描包
2、全局id類型
mybatis-plus:type-aliases-package: com.itheima.mp.domain.poglobal-config:db-config:id-type: auto # 全局id類型為自增長(zhǎng)
需要注意的是,MyBatisPlus也支持手寫SQL的,而mapper文件的讀取地址可以自己配置:+
mybatis-plus:mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件地址,當(dāng)前這個(gè)是默認(rèn)值。
可以看到默認(rèn)值是classpath*:/mapper/**/*.xml,也就是說我們只要把mapper.xml文件放置這個(gè)目錄下就一定會(huì)被加載。
Spring 工程
配置 MapperScan
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.baomidou.mybatisplus.samples.quickstart.mapper"/>
</bean>
調(diào)整 SqlSessionFactory 為 MyBatis-Plus 的 SqlSessionFactory
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/>
</bean>
常見注解
1、@TableName
用于指定數(shù)據(jù)庫(kù)表名。通常與實(shí)體類一起使用,用于映射數(shù)據(jù)庫(kù)表。
TableName注解除了指定表名以外,還可以指定很多其它屬性:
屬性 | 類型 | 必須指定 | 默認(rèn)值 | 描述 |
value | String | 否 | "" | 表名 |
schema | String | 否 | "" | schema |
keepGlobalPrefix | boolean | 否 | false | 是否保持使用全局的 tablePrefix 的值(當(dāng)全局 tablePrefix 生效時(shí)) |
resultMap | String | 否 | "" | xml 中 resultMap 的 id(用于滿足特定類型的實(shí)體類對(duì)象綁定) |
autoResultMap | boolean | 否 | false | 是否自動(dòng)構(gòu)建 resultMap 并使用(如果設(shè)置 resultMap 則不會(huì)進(jìn)行 resultMap 的自動(dòng)構(gòu)建與注入) |
excludeProperty | String[] | 否 | {} | 需要排除的屬性名 @since 3.3.1 |
2、@TableId
用于標(biāo)識(shí)實(shí)體類中的主鍵字段??梢灾付ㄖ麈I的生成策略。
TableId注解支持兩個(gè)屬性:
屬性 | 類型 | 必須指定 | 默認(rèn)值 | 描述 |
---|---|---|---|---|
value | String | 否 | "" | 表名 |
type | Enum | 否 | IdType.NONE | 指定主鍵類型 |
IdType支持的類型有:
值 | 描述 |
---|---|
AUTO | 數(shù)據(jù)庫(kù) ID 自增 |
NONE | 無狀態(tài),該類型為未設(shè)置主鍵類型(注解里等于跟隨全局,全局里約等于 INPUT) |
INPUT | insert 前自行 set 主鍵值 |
ASSIGN_ID | 分配 ID(主鍵類型為 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默認(rèn)實(shí)現(xiàn)類為DefaultIdentifierGenerator雪花算法) |
ASSIGN_UUID | 分配 UUID,主鍵類型為 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默認(rèn) default 方法) |
| 分布式全局唯一 ID 長(zhǎng)整型類型(please use ASSIGN_ID) |
| 32 位 UUID 字符串(please use ASSIGN_UUID) |
| 分布式全局唯一 ID 字符串類型(please use ASSIGN_ID) |
這里比較常見的有三種:
- AUTO:利用數(shù)據(jù)庫(kù)的id自增長(zhǎng)
- INPUT:手動(dòng)生成id
- ASSIGN_ID:雪花算法生成Long類型的全局唯一id,這是默認(rèn)的ID策略
3、@TableField
用于指定實(shí)體類字段與數(shù)據(jù)庫(kù)表字段的映射關(guān)系。它可以用于自定義列名、是否插入、更新等。
一般情況下我們并不需要給字段添加@TableField注解,一些特殊情況除外:
1、成員變量名與數(shù)據(jù)庫(kù)字段名不一致
如果實(shí)體類中的字段名與數(shù)據(jù)庫(kù)表中的列名不一致,可以使用 @TableField 注解來指定數(shù)據(jù)庫(kù)中的列名:
@TableField(value = "db_column_name")
private String entityFieldName;
2、成員變量是以 isXXX 命名
按照 JavaBean 規(guī)范,如果字段以 is 開頭,MyBatis-Plus 默認(rèn)會(huì)去掉 is 部分來進(jìn)行映射。如果數(shù)據(jù)庫(kù)字段名與去掉 is 后的變量名不一致,需要用 @TableField 指定數(shù)據(jù)庫(kù)中的列名:
@TableField(value = "db_column_name")
private Boolean isActive;
3、成員變量名與數(shù)據(jù)庫(kù)字段一致,但與數(shù)據(jù)庫(kù)關(guān)鍵字沖突
如果字段名與數(shù)據(jù)庫(kù)中的關(guān)鍵字沖突,可以使用反引號(hào) ```` 來處理:
@TableField(value = "`key`")
private String key;
支持的其它屬性如下:
屬性 | 類型 | 必填 | 默認(rèn)值 | 描述 |
value | String | 否 | "" | 數(shù)據(jù)庫(kù)字段名 |
exist | boolean | 否 | true | 是否為數(shù)據(jù)庫(kù)表字段 |
condition | String | 否 | "" | 字段 where 實(shí)體查詢比較條件,有值設(shè)置則按設(shè)置的值為準(zhǔn),沒有則為默認(rèn)全局的 %s=#{%s},參考(opens new window) |
update | String | 否 | "" | 字段 update set 部分注入,例如:當(dāng)在version字段上注解update="%s+1" 表示更新時(shí)會(huì) set version=version+1 (該屬性優(yōu)先級(jí)高于 el 屬性) |
insertStrategy | Enum | 否 | FieldStrategy.DEFAULT | 舉例:NOT_NULL insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>) |
updateStrategy | Enum | 否 | FieldStrategy.DEFAULT | 舉例:IGNORED update table_a set column=#{columnProperty} |
whereStrategy | Enum | 否 | FieldStrategy.DEFAULT | 舉例:NOT_EMPTY where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if> |
fill | Enum | 否 | FieldFill.DEFAULT | 字段自動(dòng)填充策略 |
select | boolean | 否 | true | 是否進(jìn)行 select 查詢 |
keepGlobalFormat | boolean | 否 | false | 是否保持使用全局的 format 進(jìn)行處理 |
jdbcType | JdbcType | 否 | JdbcType.UNDEFINED | JDBC 類型 (該默認(rèn)值不代表會(huì)按照該值生效) |
typeHandler | TypeHander | 否 | 類型處理器 (該默認(rèn)值不代表會(huì)按照該值生效) | |
numericScale | String | 否 | "" | 指定小數(shù)點(diǎn)后保留的位數(shù) |
條件構(gòu)造器
MyBatis-Plus 的條件構(gòu)造器(Wrapper)確實(shí)提供了強(qiáng)大且靈活的功能,用于構(gòu)建各種數(shù)據(jù)庫(kù)查詢和更新條件。
1. AbstractWrapper
AbstractWrapper 是所有 Wrapper 類的基類,定義了構(gòu)造查詢和更新條件的基礎(chǔ)方法和屬性,包括字段、值、操作符等。其他具體的 Wrapper 類(如 QueryWrapper、UpdateWrapper、LambdaQueryWrapper 和 LambdaUpdateWrapper)都繼承自它。
2. QueryWrapper
QueryWrapper 用于構(gòu)造查詢條件,支持多種操作符和邏輯組合。可以通過鏈?zhǔn)秸{(diào)用添加多個(gè)查詢條件,并通過 and 和 or 來組合條件。
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("status", 1).gt("age", 18).or().like("name", "John");List<User> users = userMapper.selectList(queryWrapper);
在上面的例子中,eq 表示等于,gt 表示大于,or 表示邏輯“或”,like 表示模糊匹配。?
3. UpdateWrapper
UpdateWrapper 用于構(gòu)造更新條件,它允許你在更新數(shù)據(jù)時(shí)指定條件。它的使用方法與 QueryWrapper 類似。
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("status", 1).set("age", 30).set("name", "Updated Name");userMapper.update(null, updateWrapper);
在這個(gè)例子中,set 用于指定需要更新的字段及其新值。?
4. LambdaQueryWrapper
LambdaQueryWrapper 允許使用 Lambda 表達(dá)式來引用實(shí)體類的屬性,避免了硬編碼字段名的問題,從而提高了代碼的可讀性和可維護(hù)性。
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(User::getStatus, 1).gt(User::getAge, 18).or().like(User::getName, "John");List<User> users = userMapper.selectList(lambdaQueryWrapper);
5. LambdaUpdateWrapper
LambdaUpdateWrapper 與 LambdaQueryWrapper 類似,但用于構(gòu)造更新條件。它允許使用 Lambda 表達(dá)式來設(shè)置更新字段及條件。
LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(User::getStatus, 1).set(User::getAge, 30).set(User::getName, "Updated Name");userMapper.update(null, lambdaUpdateWrapper);
流式查詢
MyBatis-Plus 從 3.5.4 版本開始支持流式查詢,這使得在處理大數(shù)據(jù)量時(shí)更加高效。流式查詢通過 ResultHandler 接口實(shí)現(xiàn),可以有效地避免將整個(gè)結(jié)果集加載到內(nèi)存中,適合用于數(shù)據(jù)跑批或大規(guī)模數(shù)據(jù)處理的場(chǎng)景。
常用方法
在 ResultHandler 中,可以使用以下方法來處理查詢結(jié)果:
- getResultObject(): 獲取當(dāng)前數(shù)據(jù)庫(kù)中的每一條記錄。
- getResultCount(): 獲取當(dāng)前處理的結(jié)果集條數(shù),每處理一條記錄,該計(jì)數(shù)器會(huì)加1,計(jì)數(shù)從1開始。
- stop(): 停止繼續(xù)處理結(jié)果集,相當(dāng)于在循環(huán)中使用 break 語(yǔ)句。
使用示例
以下是官網(wǎng)使用流式查詢的示例代碼,展示了如何結(jié)合分頁(yè)從數(shù)據(jù)庫(kù)中拉取數(shù)據(jù)進(jìn)行批量處理,以及如何獲取表中的所有記錄進(jìn)行處理。
// 結(jié)合分頁(yè),按批次從數(shù)據(jù)庫(kù)拉取數(shù)據(jù)出來跑批,例如從數(shù)據(jù)庫(kù)獲取10萬(wàn)記錄,做數(shù)據(jù)處理
Page<H2User> page = new Page<>(1, 100000);
baseMapper.selectList(page, Wrappers.emptyWrapper(), new ResultHandler<H2User>() {int count = 0;@Overridepublic void handleResult(ResultContext<? extends H2User> resultContext) {H2User h2User = resultContext.getResultObject();System.out.println("當(dāng)前處理第" + (++count) + "條記錄: " + h2User);// 在這里進(jìn)行你的業(yè)務(wù)處理,比如分發(fā)任務(wù)}
});// 從數(shù)據(jù)庫(kù)獲取表所有記錄,做數(shù)據(jù)處理
baseMapper.selectList(Wrappers.emptyWrapper(), new ResultHandler<H2User>() {int count = 0;@Overridepublic void handleResult(ResultContext<? extends H2User> resultContext) {H2User h2User = resultContext.getResultObject();System.out.println("當(dāng)前處理第" + (++count) + "條記錄: " + h2User);// 在這里進(jìn)行你的業(yè)務(wù)處理,比如分發(fā)任務(wù)}
});
注意事項(xiàng)
- 分頁(yè)查詢與流式查詢: 在低版本的 MyBatis-Plus 中,自定義 ResultHandler 結(jié)合分頁(yè)查詢可能會(huì)出現(xiàn)問題。解決方案是手動(dòng)關(guān)閉 count 查詢
- 資源管理: 使用流式查詢時(shí),確保數(shù)據(jù)庫(kù)連接在操作完成后被正確關(guān)閉,避免連接泄露問題。
- 性能優(yōu)化: 流式查詢適合于大數(shù)據(jù)量的場(chǎng)景,不適合處理小數(shù)據(jù)量的查詢,因其可能引入不必要的復(fù)雜性。
批量操作
批量操作是處理大量數(shù)據(jù)時(shí)的一種高效技術(shù),它通過一次性執(zhí)行多個(gè)數(shù)據(jù)庫(kù)操作來提高效率和性能。常見的批量操作包括:
- 數(shù)據(jù)插入:一次性插入多條記錄,減少SQL執(zhí)行次數(shù),加快數(shù)據(jù)寫入速度。
- 數(shù)據(jù)更新:同時(shí)更新多條記錄的特定字段,適用于批量修改數(shù)據(jù)的場(chǎng)景。
- 數(shù)據(jù)刪除:快速刪除多條記錄,適合數(shù)據(jù)清理和用戶注銷等操作。
功能概覽
- 支持版本:3.5.4及以上版本
- 事務(wù)控制:需手動(dòng)管理(默認(rèn)關(guān)閉)
- 執(zhí)行結(jié)果:返回批量處理結(jié)果,幫助判斷操作是否成功
- 數(shù)據(jù)寫入:取決于代碼是否正確執(zhí)行到flushStatements
- 兼容性:支持Spring和非Spring項(xiàng)目
- 異常類型:可能會(huì)拋出PersistenceException
- 建議:對(duì)于saveOrUpdate方法,建議簡(jiǎn)單處理新增或更新操作
類結(jié)構(gòu)說明
MybatisBatch<?>
- 泛型:實(shí)際數(shù)據(jù)類型
- sqlSessionFactory:通過容器獲取,非Spring容器下需手動(dòng)初始化
- dataList:批量數(shù)據(jù)處理列表(不能為空)
MybatisBatch.Method<?>
- 實(shí)際為BatchMethod,用于簡(jiǎn)化框架內(nèi)部操作方法的調(diào)用
- 泛型:實(shí)際Mapper方法參數(shù)類型
- mapperClass:具體的Mapper類
BatchMethod<?>
- 泛型:實(shí)際Mapper方法參數(shù)類型
- statementId:執(zhí)行的MappedStatement ID
- parameterConvert:用于數(shù)據(jù)類型與Mapper方法參數(shù)不一致時(shí)的轉(zhuǎn)換處理器
使用步驟
- 創(chuàng)建MybatisBatch實(shí)例:綁定數(shù)據(jù)列表和sqlSessionFactory。
- 創(chuàng)建MybatisBatch.Method實(shí)例:確定執(zhí)行的Mapper類方法。
- 執(zhí)行操作:將批量參數(shù)轉(zhuǎn)換為Mapper方法所需的參數(shù)。
- 處理返回值:返回List<BatchResult>,每個(gè)BatchResult代表一次MappedStatement的操作結(jié)果。
返回值說明
- 返回類型:List<BatchResult>
- 返回內(nèi)容:分組存儲(chǔ)每次MappedStatement + SQL操作的結(jié)果。例如,批量更新時(shí),返回值將根據(jù)更新字段的不同分組,顯示每組記錄的更新情況。
使用示例
execute 方法
execute 方法通常用于直接執(zhí)行批量操作,例如批量插入或更新。它通過指定的 SQL 語(yǔ)句執(zhí)行批量處理。在 MyBatis-Plus 中,這通常涉及到使用 SqlSession 執(zhí)行自定義 SQL。
public void executeBatch(List<MyEntity> entities) {SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);try {MyMapper mapper = sqlSession.getMapper(MyMapper.class);for (MyEntity entity : entities) {mapper.insert(entity); // 執(zhí)行插入操作}sqlSession.commit(); // 提交事務(wù)} catch (Exception e) {sqlSession.rollback(); // 回滾事務(wù)throw e;} finally {sqlSession.close();}
}
saveOrUpdate 方法
saveOrUpdate 方法用于處理批量保存或更新操作,自動(dòng)決定記錄是插入還是更新。+
注意:跨sqlSession下需注意緩存和數(shù)據(jù)感知問題。
public void saveOrUpdateBatch(List<MyEntity> entities) {SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);try {MyMapper mapper = sqlSession.getMapper(MyMapper.class);for (MyEntity entity : entities) {if (entity.getId() == null || mapper.selectById(entity.getId()) == null) {mapper.insert(entity); // 插入操作} else {mapper.updateById(entity); // 更新操作}}sqlSession.commit(); // 提交事務(wù)} catch (Exception e) {sqlSession.rollback(); // 回滾事務(wù)throw e;} finally {sqlSession.close();}
}
事務(wù)處理示例
在 MyBatis-Plus 中,事務(wù)管理可以通過 Spring 的事務(wù)管理器或 MyBatis 的原生事務(wù)控制進(jìn)行。
Spring 事務(wù)處理示例:
@Service
public class MyService {@Autowiredprivate MyMapper myMapper;@Transactional // 事務(wù)注解public void batchProcess(List<MyEntity> entities) {for (MyEntity entity : entities) {myMapper.insert(entity); // 執(zhí)行插入操作}}
}
手動(dòng)事務(wù)處理示例:
public void manualTransaction(List<MyEntity> entities) {SqlSession sqlSession = sqlSessionFactory.openSession();try {MyMapper mapper = sqlSession.getMapper(MyMapper.class);for (MyEntity entity : entities) {mapper.insert(entity); // 執(zhí)行插入操作}sqlSession.commit(); // 提交事務(wù)} catch (Exception e) {sqlSession.rollback(); // 回滾事務(wù)throw e;} finally {sqlSession.close();}
}
自定義SQL
sql
-- 1,刪除數(shù)據(jù)庫(kù)drop database if exists test;
-- 2,創(chuàng)建數(shù)據(jù)庫(kù)create database test;
-- 3,修改數(shù)據(jù)庫(kù)編碼方式和字符集排列順序alter database test character set utf8 collate utf8_bin;
-- 4,使用數(shù)據(jù)庫(kù)use test;-- 創(chuàng)建教師表
CREATE TABLE teacher (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL,subject VARCHAR(100) NOT NULL
);-- 創(chuàng)建班級(jí)表
CREATE TABLE class (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL,teacher_id INT,FOREIGN KEY (teacher_id) REFERENCES teacher(id)
);-- 創(chuàng)建學(xué)生表
CREATE TABLE student (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL,age INT NOT NULL,class_id INT,FOREIGN KEY (class_id) REFERENCES class(id)
);
-- 插入教師數(shù)據(jù)
INSERT INTO teacher (name, subject) VALUES
('李華', '數(shù)學(xué)'),
('張偉', '物理'),
('王芳', '歷史');-- 插入班級(jí)數(shù)據(jù),并關(guān)聯(lián)教師
INSERT INTO class (name, teacher_id) VALUES
('數(shù)學(xué)101', 1), -- 由李華教授
('物理101', 2), -- 由張偉教授
('歷史101', 3); -- 由王芳教授-- 插入學(xué)生數(shù)據(jù),并關(guān)聯(lián)班級(jí)
INSERT INTO student (name, age, class_id) VALUES
('小明', 15, 1), -- 在數(shù)學(xué)101班級(jí)
('小紅', 16, 1), -- 在數(shù)學(xué)101班級(jí)
('小剛', 15, 2), -- 在物理101班級(jí)
('小李', 17, 2), -- 在物理101班級(jí)
('小華', 16, 3); -- 在歷史101班級(jí)
查詢李華教授帶的課程,班級(jí),學(xué)生數(shù)據(jù)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.TeacherMapper"><!-- 查詢李華教授帶的課程、班級(jí)和學(xué)生數(shù)據(jù) --><select id="findTeacherClassesAndStudents" resultType="map">SELECTt.name AS teacher_name,c.name AS class_name,s.name AS student_name,s.age AS student_ageFROM teacher tJOIN class c ON t.id = c.teacher_idJOIN student s ON c.id = s.class_idWHERE t.name = '李華'</select>
</mapper>
package com.example.demo.mapper;import com.example.demo.entity.Teacher;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;/*** <p>* Mapper 接口* </p>** @author * @since 2024-09-08*/
@Mapper
public interface TeacherMapper extends BaseMapper<Teacher> {List<Map<String, Object>> findTeacherClassesAndStudents();
}
package com.example.demo.service.impl;import com.example.demo.entity.Teacher;
import com.example.demo.mapper.TeacherMapper;
import com.example.demo.service.ITeacherService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Map;/*** <p>* 服務(wù)實(shí)現(xiàn)類* </p>** @author * @since 2024-09-08*/
@Service
public class TeacherServiceImpl extends ServiceImpl<TeacherMapper, Teacher> implements ITeacherService {@Autowiredprivate TeacherMapper teacherMapper;public List<Map<String, Object>> getTeacherClassesAndStudents() {return teacherMapper.findTeacherClassesAndStudents();}
}
package com.example.demo.controller;import com.example.demo.service.impl.TeacherServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.List;
import java.util.Map;/*** <p>* 前端控制器* </p>** @author * @since 2024-09-08*/
@RestController
@RequestMapping("/teacher")
public class TeacherController {@Autowiredprivate TeacherServiceImpl teacherService;@GetMapping("/classes")public List<Map<String, Object>> getTeacherClassesAndStudents() {return teacherService.getTeacherClassesAndStudents();}
}
Service接口
MybatisPlus不僅提供了BaseMapper,還提供了通用的Service接口及默認(rèn)實(shí)現(xiàn),封裝了一些常用的service模板方法。 通用接口為IService,默認(rèn)實(shí)現(xiàn)為ServiceImpl,其中封裝的方法可以分為以下幾類:
- save:新增
- remove:刪除
- update:更新
- get:查詢單個(gè)結(jié)果
- list:查詢集合結(jié)果
- count:計(jì)數(shù)
- page:分頁(yè)查詢
CRUD
我們先倆看下基本的CRUD接口。
新增:
- ?save - 新增單個(gè)元素:用于新增單個(gè)記錄。它會(huì)根據(jù)實(shí)體類的字段進(jìn)行插入操作。
- ?saveBatch - 批量新增:用于批量新增多條記錄。適合在一次操作中插入多個(gè)實(shí)體對(duì)象,提高插入效率。
- saveOrUpdate - 根據(jù) ID 判斷新增或更新:如果實(shí)體對(duì)象的 ID 存在于數(shù)據(jù)庫(kù)中,則執(zhí)行更新操作;如果 ID 不存在,則執(zhí)行插入操作。
- saveOrUpdateBatch - 批量的新增或修改:批量處理實(shí)體對(duì)象,根據(jù)每個(gè)對(duì)象的 ID 判斷是執(zhí)行插入還是更新操作。
刪除:
???????
- removeById - 根據(jù) ID 刪除:刪除指定 ID 的記錄。
- removeByIds - 批量根據(jù) ID 刪除:刪除多個(gè)指定 ID 的記錄。
- removeByMap - 根據(jù) Map 中的條件刪除:根據(jù) Map 中的鍵值對(duì)作為條件進(jìn)行刪除。
- remove(Wrapper<T>) - 根據(jù) Wrapper 條件刪除:使用 Wrapper 對(duì)象中定義的條件進(jìn)行刪除。
- removeBatchByIds 方法已不再支持,建議使用 removeByIds 進(jìn)行批量刪除操作。
修改:
- updateById - 根據(jù) ID 修改:根據(jù)指定 ID 更新記錄。需要提供更新后的實(shí)體對(duì)象。
- update(Wrapper<T>) - 根據(jù) UpdateWrapper 修改:使用 UpdateWrapper 進(jìn)行條件更新。需要定義更新的字段和條件。
- update(T, Wrapper<T>) - 按照實(shí)體數(shù)據(jù)和 Wrapper 修改:根據(jù)實(shí)體對(duì)象中的數(shù)據(jù)和 Wrapper 中的條件進(jìn)行更新。實(shí)體對(duì)象中的字段會(huì)被更新到符合 Wrapper 條件的記錄中。
- updateBatchById - 根據(jù) ID 批量修改:根據(jù)多個(gè) ID 批量更新記錄。實(shí)體對(duì)象中的數(shù)據(jù)會(huì)更新到對(duì)應(yīng)的 ID 中。
Get:
- getById - 根據(jù) ID 查詢:根據(jù)指定 ID 獲取一條記錄。
- getOne(Wrapper<T>) - 根據(jù) Wrapper 查詢:使用 Wrapper 條件獲取一條記錄。如果有多條記錄符合條件,只會(huì)返回其中一條。
- getBaseMapper - 獲取 BaseMapper 實(shí)現(xiàn):獲取 Service 內(nèi)的 BaseMapper 實(shí)現(xiàn),以便進(jìn)行自定義 SQL 操作或其他特殊操作。
List:
- listByIds - 根據(jù) ID 批量查詢:根據(jù)多個(gè) ID 獲取對(duì)應(yīng)的記錄。
- list(Wrapper<T>) - 根據(jù) Wrapper 條件查詢:使用 Wrapper 條件獲取多條記錄。
- list() - 查詢所有:獲取所有記錄。
Count:
- count() - 統(tǒng)計(jì)所有記錄的數(shù)量:統(tǒng)計(jì)數(shù)據(jù)庫(kù)中所有記錄的總數(shù)。
- count(Wrapper<T>) - 統(tǒng)計(jì)符合 Wrapper 條件的記錄數(shù)量:使用 Wrapper 條件統(tǒng)計(jì)符合條件的記錄數(shù)量。
getBaseMapper:
getBaseMapper 方法允許在 Service 中直接獲取 Mapper 實(shí)現(xiàn),以便執(zhí)行自定義 SQL 查詢或操作。
TeacherMapper teacherMapper = teacherService.getBaseMapper();
List<Teacher> teachers = teacherMapper.customQueryMethod();
這樣,可以在 Mapper 中定義自定義的 SQL 方法,并通過 getBaseMapper 直接調(diào)用。
擴(kuò)展功能
代碼生成
MybatisPlus 提供的代碼生成器可以大大簡(jiǎn)化代碼編寫工作,但使用起來可能有些復(fù)雜。推薦的圖形化插件能夠通過友好的界面完成代碼生成,簡(jiǎn)化了配置和操作流程。這樣的工具能有效提升開發(fā)效率,減少手動(dòng)編寫基礎(chǔ)代碼的工作量。
安裝插件
在Idea的plugins市場(chǎng)中搜索并安裝MyBatisPlus插件:
然后重啟你的Idea即可使用。
通用枚舉
sql
-- 1,刪除數(shù)據(jù)庫(kù)drop database if exists test;
-- 2,創(chuàng)建數(shù)據(jù)庫(kù)create database test;
-- 3,修改數(shù)據(jù)庫(kù)編碼方式和字符集排列順序alter database test character set utf8 collate utf8_bin;
-- 4,使用數(shù)據(jù)庫(kù)use test;-- 創(chuàng)建教師表
CREATE TABLE teacher (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL,subject VARCHAR(100) NOT NULL
);-- 創(chuàng)建班級(jí)表
CREATE TABLE class (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL,teacher_id INT,FOREIGN KEY (teacher_id) REFERENCES teacher(id)
);-- 創(chuàng)建學(xué)生表
CREATE TABLE student (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL,age INT NOT NULL,class_id INT,gender ENUM('Male', 'Female') NOT NULL,FOREIGN KEY (class_id) REFERENCES class(id)
);-- 插入教師數(shù)據(jù)
INSERT INTO teacher (name, subject) VALUES
('李華', '數(shù)學(xué)'),
('張偉', '物理'),
('王芳', '歷史');-- 插入班級(jí)數(shù)據(jù),并關(guān)聯(lián)教師
INSERT INTO class (name, teacher_id) VALUES
('數(shù)學(xué)101', 1),
('物理101', 2),
('歷史101', 3);-- 插入學(xué)生數(shù)據(jù),并關(guān)聯(lián)班級(jí)
INSERT INTO student (name, age, class_id, gender) VALUES
('小明', 15, 1, 'Male'),
('小紅', 16, 1, 'Female'),
('小剛', 15, 2, 'Male'),
('小李', 17, 2, 'Male'),
('小華', 16, 3, 'Female');
定義通用枚舉
public enum Gender {MALE("Male"),FEMALE("Female");private final String description;Gender(String description) {this.description = description;}public String getDescription() {return description;}
}
假設(shè)在 Java 中處理這些數(shù)據(jù),可以在實(shí)體類中添加枚舉字段:?
public class Student {private Long id;private String name;private int age;private Long classId;private Gender gender;
}
配置枚舉處理器
在application.yaml文件中添加配置:
mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
插件功能
- PaginationInnerInterceptor(自動(dòng)分頁(yè)):自動(dòng)處理分頁(yè)查詢。
- TenantLineInnerInterceptor(多租戶):實(shí)現(xiàn)多租戶功能,通過 SQL 查詢條件自動(dòng)添加租戶信息。
- DynamicTableNameInnerInterceptor(動(dòng)態(tài)表名):允許動(dòng)態(tài)更改 SQL 查詢中的表名。
- OptimisticLockerInnerInterceptor(樂觀鎖):實(shí)現(xiàn)樂觀鎖機(jī)制,避免數(shù)據(jù)的并發(fā)更新沖突。
- IllegalSQLInnerInterceptor(SQL 性能規(guī)范):檢查 SQL 語(yǔ)句的規(guī)范性,避免不合理的 SQL。
- BlockAttackInnerInterceptor(防止全表更新與刪除):防止全表更新和刪除操作,避免誤操作。
插件定義順序
使用多個(gè)插件時(shí),需要注意插件的定義順序以確保插件功能的正常運(yùn)行。通常的順序如下:
- 多租戶(TenantLineInnerInterceptor)
- 動(dòng)態(tài)表名(DynamicTableNameInnerInterceptor)
- 分頁(yè)(PaginationInnerInterceptor)
- 樂觀鎖(OptimisticLockerInnerInterceptor)
- SQL 性能規(guī)范(IllegalSQLInnerInterceptor)
- 防止全表更新與刪除(BlockAttackInnerInterceptor)
配置示例
下面是一個(gè)示例配置,演示如何按照順序注冊(cè)這些插件:
package com.example.demo.Config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** MybatisPlus配置類* 用于配置MybatisPlus的相關(guān)插件*/
@Configuration
public class MybatisPlusConfig {/*** 配置MybatisPlus攔截器* 攔截器用于處理租戶、動(dòng)態(tài)表名、分頁(yè)、樂觀鎖、非法SQL和防注入攻擊等功能** @return 配置好的MybatisPlusInterceptor對(duì)象*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加租戶攔截器,處理多租戶場(chǎng)景下的數(shù)據(jù)隔離interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(/* TenantLineHandler */));// 添加動(dòng)態(tài)表名攔截器,支持動(dòng)態(tài)表名interceptor.addInnerInterceptor(new DynamicTableNameInnerInterceptor(/* DynamicTableNameHandler */));// 添加分頁(yè)攔截器,實(shí)現(xiàn)分頁(yè)功能interceptor.addInnerInterceptor(new PaginationInnerInterceptor());// 添加樂觀鎖攔截器,支持樂觀鎖機(jī)制interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());// 添加非法SQL攔截器,防止非法SQL注入interceptor.addInnerInterceptor(new IllegalSQLInnerInterceptor());// 添加防注入攻擊攔截器,增強(qiáng)SQL安全性interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());return interceptor;}
}
這里我們以分頁(yè)插件為里來學(xué)習(xí)插件的用法。
package com.example.demo.entity;import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;/*** <p>* * </p>** @author * @since 2024-09-08*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("student")
public class Student implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "id", type = IdType.AUTO)private Integer id;private String name;private Integer age;private Integer classId;private String gender;
}
package com.example.demo.mapper;import com.example.demo.entity.Student;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;/*** <p>* Mapper 接口* </p>** @author * @since 2024-09-08*/
public interface StudentMapper extends BaseMapper<Student> {}
package com.example.demo.controller;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.Student;
import com.example.demo.service.impl.StudentServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** <p>* 前端控制器* </p>** @author* @since 2024-09-08*/
@RestController
public class StudentController {@Autowiredprivate StudentServiceImpl studentService;@GetMapping("/students")public Page<Student> getStudentsByAge(@RequestParam int age,@RequestParam(defaultValue = "1") int page,@RequestParam(defaultValue = "10") int size) {return studentService.getStudentsByAge(age, page, size);}
}
啟動(dòng)Spring Boot項(xiàng)目后,訪問以下URL進(jìn)行分頁(yè)查詢:
http://localhost:8080/students?age=17&page=1&size=10
這將返回年齡為17的學(xué)生信息,每頁(yè)10條記錄,并以JSON格式返回。