MyBatisPlus学习笔记 学习使用看这一篇就够了(上)
@[toc]
前言
本篇博客是MyBatisPlus实际应用的学习笔记,若文章中出现相关问题,请指出!
所有博客文件目录索引:博客目录索引(持续更新)
导航
工具接口及类
BaseMapper
BaseMapper
是mp
提供给我们用于增强mapper
接口方法:覆盖了大量的针对于单表的查询操作
public interface BaseMapper<T> extends Mapper<T> {
//新增
int insert(T entity);
int deleteById(Serializable id);
//根据字段删除
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> wrapper);
//批量删除
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
//单条更新
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
//单条查询根据id
T selectById(Serializable id);
//查询多条记录根据id
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
//查询多条记录根据属性字段
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
IService与ServiceImpl(接口定义与实现)
下面是ServiceImpl给我们实现的抽象类方法
你能想到的单表查询几乎都有。
public interface IService<T> {
int DEFAULT_BATCH_SIZE = 1000;
default boolean save(T entity) {
return SqlHelper.retBool(this.getBaseMapper().insert(entity));
}
@Transactional(
rollbackFor = {Exception.class}
)
default boolean saveBatch(Collection<T> entityList) {
return this.saveBatch(entityList, 1000);
}
boolean saveBatch(Collection<T> entityList, int batchSize);
@Transactional(
rollbackFor = {Exception.class}
)
default boolean saveOrUpdateBatch(Collection<T> entityList) {
return this.saveOrUpdateBatch(entityList, 1000);
}
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
default boolean removeById(Serializable id) {
return SqlHelper.retBool(this.getBaseMapper().deleteById(id));
}
default boolean removeByMap(Map<String, Object> columnMap) {
Assert.notEmpty(columnMap, "error: columnMap must not be empty", new Object[0]);
return SqlHelper.retBool(this.getBaseMapper().deleteByMap(columnMap));
}
default boolean remove(Wrapper<T> queryWrapper) {
return SqlHelper.retBool(this.getBaseMapper().delete(queryWrapper));
}
default boolean removeByIds(Collection<? extends Serializable> idList) {
return CollectionUtils.isEmpty(idList) ? false : SqlHelper.retBool(this.getBaseMapper().deleteBatchIds(idList));
}
default boolean updateById(T entity) {
return SqlHelper.retBool(this.getBaseMapper().updateById(entity));
}
default boolean update(Wrapper<T> updateWrapper) {
return this.update((Object)null, updateWrapper);
}
default boolean update(T entity, Wrapper<T> updateWrapper) {
return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
}
@Transactional(
rollbackFor = {Exception.class}
)
default boolean updateBatchById(Collection<T> entityList) {
return this.updateBatchById(entityList, 1000);
}
boolean updateBatchById(Collection<T> entityList, int batchSize);
boolean saveOrUpdate(T entity);
default T getById(Serializable id) {
return this.getBaseMapper().selectById(id);
}
default List<T> listByIds(Collection<? extends Serializable> idList) {
return this.getBaseMapper().selectBatchIds(idList);
}
default List<T> listByMap(Map<String, Object> columnMap) {
return this.getBaseMapper().selectByMap(columnMap);
}
default T getOne(Wrapper<T> queryWrapper) {
return this.getOne(queryWrapper, true);
}
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
Map<String, Object> getMap(Wrapper<T> queryWrapper);
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
default int count() {
return this.count(Wrappers.emptyWrapper());
}
default int count(Wrapper<T> queryWrapper) {
return SqlHelper.retCount(this.getBaseMapper().selectCount(queryWrapper));
}
default List<T> list(Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectList(queryWrapper);
}
default List<T> list() {
return this.list(Wrappers.emptyWrapper());
}
default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectPage(page, queryWrapper);
}
default <E extends IPage<T>> E page(E page) {
return this.page(page, Wrappers.emptyWrapper());
}
default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectMaps(queryWrapper);
}
default List<Map<String, Object>> listMaps() {
return this.listMaps(Wrappers.emptyWrapper());
}
default List<Object> listObjs() {
return this.listObjs(Function.identity());
}
default <V> List<V> listObjs(Function<? super Object, V> mapper) {
return this.listObjs(Wrappers.emptyWrapper(), mapper);
}
default List<Object> listObjs(Wrapper<T> queryWrapper) {
return this.listObjs(queryWrapper, Function.identity());
}
default <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
return (List)this.getBaseMapper().selectObjs(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
}
default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectMapsPage(page, queryWrapper);
}
default <E extends IPage<Map<String, Object>>> E pageMaps(E page) {
return this.pageMaps(page, Wrappers.emptyWrapper());
}
BaseMapper<T> getBaseMapper();
default QueryChainWrapper<T> query() {
return ChainWrappers.queryChain(this.getBaseMapper());
}
default LambdaQueryChainWrapper<T> lambdaQuery() {
return ChainWrappers.lambdaQueryChain(this.getBaseMapper());
}
default UpdateChainWrapper<T> update() {
return ChainWrappers.updateChain(this.getBaseMapper());
}
default LambdaUpdateChainWrapper<T> lambdaUpdate() {
return ChainWrappers.lambdaUpdateChain(this.getBaseMapper());
}
default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);
}
}
IPage与Page
在Page对象中,包含了关于分页的相关信息,其中包含对应的查询结果集records以及对于分页的相关属性:
可以说满足了基本的需求了。
一、springboot集成Mybatis plus实现CRUD
前提准备
引入依赖:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
yml配置项:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mybatisplusExer?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
# 启动时需要初始化的建表sql语句
schema: classpath:sql/schema.sql
# 执行好就修改为never
initialization-mode: always # always为始终执行初始化,embedded只初始化内存数据库(默认值),如h2等,never为不执行初始化
#控制台打印sql(默认不会有打印sql语句)
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 默认开启时会进行pojo字段映射如:lastName => last_name
mapUnderscoreToCamelCase: false # 取消自动驼峰命名规则映射(默认是开启的),这里仅仅是用于测试
sql
:
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
DELETE FROM user;
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');
pojo
:
/**
* @ClassName User
* @Author ChangLu
* @Date 2021/8/16 22:11
* @Description TODO
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User { //mp会默认将pojo类名当做表名(首字母小写),若是类名与表名不一致可使用注解
//默认会识别id作为主键,这里是对id自动生成进行设置: IdType.AUTO为自动,还有其他很多策略
@TableId(value = "id",type = IdType.AUTO)
private Long id;
// 设置表字段别名(当表属性不一致时即可进行指定) 默认是自动开启别名转换的(这里只是为了熟悉使用)
@TableField("last_name")
private String lastName; //建议pojo字段名与表名像lastName=>last_name要对应,否则使用(如name=>last_name)包装器select()查询返回赋值会无效。
private Integer age;
private String email;
}
- 默认mybatis-plus中会将你的pojo类自动进行转换,如字段lastName,之后来查询数据库会自动转为last_name来进行查询。
- 若是你插入一条数据的id(mp默认会认为你的id为主键id)没有设置,mp会自动帮你生成一个全局唯一的id(字符串)!并且你插入后该对象就会得到对应自动生成的id值。
UserMapper
:
/**
* @ClassName UserMapper
* @Author ChangLu
* @Date 2021/8/16 22:11
* @Description TODO
*/
public interface UserMapper extends BaseMapper<User> {
}
springboot启动类上标注自动扫描mapper包:
@MapperScan("com.changlu.mybatisplusexer.mapper")
CRUD操作
这里暂时没有Wrapper相关的操作,只是进行了对selectByMap
及deleteByMap
以及其他普通的测试用例,其是根据传入map的属性来进行字段查询的,可设置多个字段,这里仅有一个字段。
特别说明的是:mp中对于查询的键值对,传入与数据库中不同类型的也可以兼容,真的是强大呀,例如数据库中的age字段为int类型,你设置map属性字段中传入put(“age”,“20”)也完全是ok的。
import com.changlu.mybatisplusexer.mapper.UserMapper;
import com.changlu.mybatisplusexer.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
class MybatisplusexerApplicationTests {
@Resource
private UserMapper userMapper;
@Test
void queryAll() {
System.out.println(("----- selectAll method test ------"));
List<User> userList = userMapper.selectList(null);
userList.forEach(System.out::println);
}
@Test
void query(){
System.out.println(userMapper.selectById(1));
}
@Test
void query2(){ //selectByMap测试:根据条件筛选
Map<String, Object> columnMap = new HashMap<>(1);
columnMap.put("age",20);//条件为age=20
List<User> users = userMapper.selectByMap(columnMap);
System.out.println(users);
}
@Test
void insert(){
User user = new User(null, "changlu", 18, "939974883@qq.com");
//执行保存sql前会先生成id到user中
int result = userMapper.insert(user);
System.out.println("user=>"+user+",result=>"+result);
}
@Test
public void delete(){
int result = userMapper.deleteById(1);
System.out.println(result);
}
@Test
public void delete2(){ //deleteByMap:根据指定字段删除
Map<String, Object> columnMap = new HashMap<>(1);
columnMap.put("age","20");//条件为age=20,
int result = userMapper.deleteByMap(columnMap);
System.out.println(result);
}
@Test
public void update(){
User user = new User((long)2, "changlu", 20, "939974883@qq.com");
int result = userMapper.updateById(user);
System.out.println(result);
}
}
二、通用IService使用
在一中介绍的是对mapper接口进行的增强,在mp中还可以对service进行增强,也就是说一些常见的普通的service方法已经帮你进行封账好了,能够更快的进行一系列的操作。
说明:
//更新操作
//①若是更新某个model实体类,使用updateWrapper一定要进行指定id,否则就会更新整张表
//②若是批量对多个model的某个字段进行更新,调用方法
updateBatchById()
save():执行完后返回的是一个布尔值,表示是否插入成功,并且若是你没有填写id,会自动先生成主键到指定实体类中,再进行执行sql保存操作
准备
在示例一的基础上,我们来添加service接口以及service实现类,对应的接口需要实现IService,实现类需要继承一个抽象Service,同样也是mp给我们封装号的对应增强方法接口的实现体。
UserService
:service接口定义
public interface UserService extends IService<User> {
}
UserServiceImpl
:实现类定义
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
测试
在mp给我们提供的service方法中,对于增删改操作也都包含了对应的事务处理,总体来说还是特别方便的!
@SpringBootTest
class MybatisplusexerApplicationTests {
@Autowired
private UserService userService;
//saveOrUpdate:先根据id查,若是有则进行更新,没有进行插入
@Test
public void saveOrUpdate(){
//测试插入
User user = new User((long)1,"changlu",18,"9999");
boolean b = userService.saveOrUpdate(user);//true:成功;false:失败
System.out.println(b);
}
//saveOrUpdate:先根据id查,若是有则进行更新,没有进行插入
@Test
public void saveOrUpdate2(){
//测试更新
User user = new User((long)1,"liner",22,"368");
boolean b = userService.saveOrUpdate(user);
System.out.println(b);
}
//listByIds:根据多个id来进行批量查询。(底层采用in方式来进行查询)
@Test
public void query(){
List<User> users = userService.listByIds(Arrays.asList(1, 3, 5));
System.out.println(users);
}
}
三、分页查询
3.1中的分页方法只对调用IService里的分页方法才有效!
我们编写请求实现类时,若是进行分页可以直接继承下面的实体类就是表示分页和:
@Data
public class BasePage implements Serializable {
private static final long serialVersionUID = 8491572200460447988L;
protected long size = 10;
protected long current = 1;
}
3.1、借助mp的分页插件
准备 分页插件
在mp的Iservice
中提高了四个分页方法:
在BaseMapper中提供了两个分页方法:
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
注意:要想使用mp中的分页功能,就必须需要安装分页插件,否则不会生效!
step1:编写一个mp的配置类,在该配置类中添加分页插件
@Configuration
@MapperScan("com.changlu.mybatisplusexer.mapper") //使用了分配类,即可将启动器的自动打包放置在这里
public class MybatisPlusConfig {
// 最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //设置方言为MySQL
return interceptor;
}
}
实操
数据库中有四条记录,我们来对其进行测试:
@SpringBootTest
class MybatisplusexerApplicationTests {
@Autowired
private UserService userService;
@Test
public void saveOrUpdate() throws JsonProcessingException {
//当前页与每页数量
IPage<User> page = new Page<>(1,2);
//分页查询
IPage<User> pageResult = userService.page(page);
//对象转JSON字符串
ObjectMapper om = new ObjectMapper();
String json = om.writeValueAsString(pageResult);
System.out.println(json);
}
}
可以看到查询了两条sql,一个是查询数量,另一个是进行limit查询操作!
为了方便查看Page的相关属性,我们将其转为JSON字符串并且借助工具网站来美化显示其中的内容:
- records:分页查询的记录结果。
- total:总记录数。
- size:每页显示条数,根据初始定义的Page决定。
- current:当前页。
- pages:总共2页。
这样的结果内容,对于前台简直不要太舒服了!!!
3.2、XML 自定义分页
前提准备 XML 自定义分页
对于我们自定义sql语句,也就是书写xml也可以实现自定义分页!
在mp中我们无需指定mapper位置,因为对应springboot启动器已经为我们设置默认mapper读取位置:
若是我们想要修改mapper映射配置的位置,直接在yml配置中进行配置即可:
mybatis-plus:
mapper-locations: classpath*:/mapperxxx/**/*.xml
<br/0
实操
直接在resources下的mapper文件夹中编写xml配置文件:
<?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.changlu.mybatisplusexer.mapper.UserMapper">
<select id="queryByAge" resultType="com.changlu.mybatisplusexer.pojo.User">
select * from Blog where age = #{age}
</select>
</mapper>
若是想要对xml的查询结果进行分页,那么只需要在mapper中接口返回值以及属性中设置即可!
public interface UserMapper extends BaseMapper<User> {
//此时就会根据我们传入的page来进行对结果进行分页返回
IPage<User> queryByAge(Page<?> page,Integer age);
}
测试一下:
@Resource
private UserMapper userMapper;
@Test
public void saveOrUpdate() throws JsonProcessingException {
//当前页与每页数量
Page<User> page = new Page<>(1,1);
IPage<User> userIPage = userMapper.queryByAge(page, 22);
String json = new ObjectMapper().writeValueAsString(userIPage);
System.out.println(json);
}
根据设置的Page信息,查询出来的分页内容与实际情况符合,分页完成!
3.3、第三方插件:PageHelper
原理分析
底层使用了一个PageInterceptor分页拦截器
提前准备
引入依赖:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
注意一下:若是你同时引入mybatis-plus以及pagehelper启动器依赖,运行时就会报异常如下。
如何解决呢?将对应pagehelper启动器中的指定mybatis依赖移除即可。
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.1</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
实操
主要就是test方法中的第1以及第3行,即可实现分页效果!
@GetMapping("/")
public ResultBody test(@RequestParam("pagenum")Integer pageNum,@RequestParam("pagesize")Integer pageSize){
PageHelper.startPage(pageNum,pageSize);//设置起始页以及每页数量
List<User> users = userMapper.selectList(null);//此时底层对于select就是进行分页来得到的结果集
PageInfo<User> userPageInfo = new PageInfo<>(users);//封装PageInfo对象
return ResultBody.success(userPageInfo);
}
最终拿到的返回值对象:其中包含了很多的关于分页的属性,前端判断就更加容易了
- 点赞
- 收藏
- 关注作者
评论(0)