Mybatis Plus之內(nèi)置Mapper實(shí)踐
MyBatis Plus,作為對MyBatis的進(jìn)一步增強(qiáng),大大簡化了我們的開發(fā)流程,提高了開發(fā)速度

配置
由于Mybatis Plus是建立在Mybatis之上的,所以其已經(jīng)依賴了Mybatis,故我們無需在項(xiàng)目中顯式地重復(fù)添加Mybatis依賴。直接在POM文件中Mybatis Plus依賴即可
<!--Mybatis Plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
Mapper CRUD操作
在Mybatis下,需要我們自行編寫Mapper接口文件、提供sql的的xml文件。眾所周知,這些CRUD的接口寫起來不僅繁瑣還容易出錯(cuò),為此在Mybatis Plus中提供了內(nèi)置的Mapper。高效實(shí)現(xiàn)CRUD操作
-- 創(chuàng)建數(shù)據(jù)表
create table t_people_info (
id int not null auto_increment comment 'ID',
username varchar(255) null comment '姓名',
sex varchar(255) null comment '性別',
primary key (id)
) comment '信息表';
POJO類定義如下,這里展示了@TableName、@TableField注解的用法
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_people_info") // 指定數(shù)據(jù)庫的表名
public class People {
/**
* ID
*/
private int id;
/**
* 姓名
*/
@TableField("name") // 該屬性在數(shù)據(jù)表中對應(yīng)的字段名
private String username;
/**
* 性別
*/
private String sex;
/**
* 職業(yè)
*/
@TableField(exist = false) // 該屬性在數(shù)據(jù)表中不存在
private String job;
}
而Mapper接口文件只需繼承BaseMapper即可獲得Mybatis Plus提供的基本的CRUD功能,無需我們定義接口及相關(guān)的SQL。當(dāng)然如果需要復(fù)雜的操作直接在PeopleMapper接口中繼續(xù)添加即可
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface PeopleMapper extends BaseMapper<People> {
}
增
public class ProperService {
@Autowired
private PeopleMapper peopleMapper;
public void testInsert() {
List<People> list = new LinkedList<>();
list.add( People.builder().username("小明").build() );
list.add( People.builder().id(10).username("老王").sex("男").build() );
list.add( People.builder().id(11).username("老張").sex("女").build() );
list.add( People.builder().id(12).sex("女").build() );
for (People people : list) {
peopleMapper.insert(people);
}
}
}
刪
根據(jù)ID刪除及批量操作,方式如下
/**
* 根據(jù)ID刪除
*/
public void testDeleteById() {
peopleMapper.deleteById(10);
}
/**
* 根據(jù)ID批量刪除
*/
public void testDeleteByIds() {
List ids = new LinkedList();
ids.add(11);
ids.add(12);
peopleMapper.deleteBatchIds( ids );
}
與此同時(shí),也支持基于條件的刪除
/**
* 根據(jù)條件刪除
*/
public void testDeleteByParam1() {
// 表字段map
Map map = new HashMap();
// Note:這里設(shè)置條件應(yīng)使用數(shù)據(jù)表的字段名,而不是Java類的屬性名
map.put("name", "匿名用戶");
map.put("sex", "男");
// 多個(gè)條件為and的關(guān)系
int num = peopleMapper.deleteByMap(map);
System.out.println("delete num : " + num);
}
/**
* 根據(jù)條件刪除
*/
public void testDeleteByParam2() {
// Note:此時(shí)其實(shí)隱含了 id為null 的條件
People people = People.builder()
.username("翠花")
.sex("女")
.build();
// 多個(gè)條件為and的關(guān)系
QueryWrapper<People> wrapper = new QueryWrapper<>(people);
int num = peopleMapper.delete( wrapper );
System.out.println("delete num : " + num);
}
改
同理對于更新操作,支持基于ID的操作方式
/**
* 根據(jù)ID更新
*/
public void testUpdateById() {
People people = People.builder()
.id(3)
.username("孫尚香")
.build();
peopleMapper.updateById(people);
}
上述更新語句執(zhí)行后會(huì)發(fā)現(xiàn),id為3的記錄,對于name字段確實(shí)被更新為 "孫尚香" 了,但是如果sex字段并不會(huì)被更新為 NULL。這是因?yàn)锧TableField注解的updateStrategy屬性默認(rèn)為NOT_NULL所導(dǎo)致的。該屬性常用的值及釋義如下所示
NOT_NULL:要求新值非NULL NOT_EMPTY:要求新值非NULL、非空字符串 IGNORED:新值可以為NULL、空字符串
故我們在sex屬性上使用@TableField注解,并把updateStrategy設(shè)置為FieldStrategy.IGNORED后,上述測試代碼對sex字段的更新才會(huì)生效
/**
* 性別
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String sex;
與此同時(shí),也支持基于條件的更新。而且可以看到在基于ID的更新方式中,需要修改@TableField注解的updateStrategy屬性,來保證可以更新為NULL、空字符串。顯然非常麻煩,而且容易出錯(cuò)。而通過updateWrapper的set方法來設(shè)置新值,顯式地設(shè)置NULL值就非常直觀了,不容易出錯(cuò)
/**
* 根據(jù)條件更新
*/
public void testUpdateByParam() {
UpdateWrapper<People> updateWrapper = new UpdateWrapper<>();
// Note:這里應(yīng)使用數(shù)據(jù)表的字段名,而不是Java類的屬性名
// where 條件:id 大于 50
updateWrapper.gt("id",50);
// set 新值:sex 更新為 男
updateWrapper.set("sex","男");
// set 新值:name 更新為 NULL
updateWrapper.set("name","null");
// 多個(gè)條件為and的關(guān)系
peopleMapper.update(null, updateWrapper);
}
查
根據(jù)ID查詢及批量操作,方式如下
/**
* 根據(jù)ID查詢
*/
public void testSelectById() {
People people = peopleMapper.selectById(1);
System.out.println("people: " + people);
}
/**
* 根據(jù)ID批量查詢
*/
public void testSelectByIds() {
List list = new LinkedList();
list.add(1);
list.add(2);
list.add(3);
List<People> peopleList = peopleMapper.selectBatchIds(list);
peopleList.forEach(System.out::println);
}
與此同時(shí),也支持基于條件的查詢。其中查詢條件為空,則查詢?nèi)?/p>
/**
* 根據(jù)條件查詢。其中查詢條件為空,則查詢?nèi)?br> */
public void testSelectAll() {
List<People> list = peopleMapper.selectList(null);
list.forEach( System.out::println );
}
/**
* 根據(jù)條件查詢
*/
public void testSelectByParam1() {
QueryWrapper<People> queryWrapper = new QueryWrapper<>();
// Note:這里設(shè)置條件應(yīng)使用數(shù)據(jù)表的字段名,而不是Java類的屬性名
// 條件:性別為男
queryWrapper.eq("sex", "男");
// 條件:id 小于等于 100
queryWrapper.le("id", 50);
// 多個(gè)條件為and的關(guān)系
List<People> list = peopleMapper.selectList(queryWrapper);
list.forEach(System.out::println);
}
/**
* 根據(jù)條件查詢
*/
public void testSelectByParam2() {
// 表字段map
Map<String, Object> map = new HashMap<>();
map.put("sex", "女");
// Note:這里設(shè)置條件應(yīng)使用數(shù)據(jù)表的字段名,而不是Java類的屬性名
map.put("name", "佳麗");
// 多個(gè)條件為and的關(guān)系
List<People> list = peopleMapper.selectByMap(map);
list.forEach(System.out::println);
}
有時(shí)候我們還需要進(jìn)行分頁查詢,在Mybatis Plus下也是非常方便的,只需配置下分頁插件即可
@Configuration
public class MybatisPlusConfig {
/**
* Mybatis Plus 分頁插件
* @return
*/
@Bean
public MybatisPlusInterceptor innerInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
關(guān)于分頁查詢的操作方式如下所示:
/**
* 分頁查詢
*/
public void testSelectByPage() {
// 查詢條件
QueryWrapper<People> queryWrapper = new QueryWrapper<>();
// Note:這里設(shè)置條件應(yīng)使用數(shù)據(jù)表的字段名,而不是Java類的屬性名
// 條件:id 大于 2
queryWrapper.gt("id", 2);
// 條件:name字段 (右)模糊匹配 "張%"
queryWrapper.likeRight("name", "張");
// 分頁參數(shù): 頁碼:2, 單頁大小:10
Page<People> page = new Page<>(2,10);
// 分頁查詢, 多個(gè)條件為and的關(guān)系
Page<People> result = peopleMapper.selectPage(page2, queryWrapper);
System.out.println("people List: " + result.getRecords() );
}
邏輯刪除
對于內(nèi)置Mapper,Mybatis Plus可以自動(dòng)支持邏輯刪除的功能。通過@TableLogic注解指定邏輯刪除字段即可
/**
* 邏輯刪除標(biāo)識,invalid:無效;valid:有效
*/
@TableLogic
private String flag;
而對于邏輯未刪除的值、已刪除的值即可直接通過注解配置,亦可進(jìn)行全局配置
# Mybatis Plus 全局設(shè)置,邏輯已刪除值
mybatis-plus.global-config.db-config.logic-delete-value=invalid
# Mybatis Plus 全局設(shè)置,邏輯未刪除值
mybatis-plus.global-config.db-config.logic-not-delete-value=valid
為了實(shí)現(xiàn)邏輯刪除,內(nèi)置Mapper在自動(dòng)注入SQL時(shí)也會(huì)發(fā)生一些變化。具體地:
插入:無變化 查找:一方面會(huì)追加where條件以過濾掉已刪除的記錄,另一方面,通過wrapper指定條件也會(huì)忽略邏輯刪除字段的條件 更新:一方面會(huì)追加where條件防止對已刪除的記錄進(jìn)行更新,另一方面,通過wrapper指定條件也會(huì)忽略邏輯刪除字段的條件 刪除:轉(zhuǎn)變?yōu)楦抡Z句,將 邏輯刪除字段 設(shè)置為 邏輯已刪除值
Note
對于主鍵,Mybatis Plus還支持在未指定主鍵的時(shí)候自動(dòng)生成ID或UUID。具體地,其支持對某個(gè)表的單獨(dú)設(shè)置、全局設(shè)置。前者可通過在主鍵屬性上設(shè)置@TableId注解的type屬性為IdType.ASSIGN_ID、IdType.ASSIGN_UUID實(shí)現(xiàn);后者則可通過在配置文件中設(shè)置配置項(xiàng) mybatis-plus.global-config.db-config.id-type 為 assign_id、assign_uuid 實(shí)現(xiàn)
