1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > mybatis学习笔记——mybatis-plus快速入门

mybatis学习笔记——mybatis-plus快速入门

时间:2019-07-08 05:49:36

相关推荐

mybatis学习笔记——mybatis-plus快速入门

一、快速入门

MyBatis-plus (简称mp)是一款 Mybatis 增强工具,用来简化开发、增强效率。本文结合Spring Boot来实现mp的快速入门。

注:本文演示mp版本为当前最新的3.5.1

官方网站:/

1、创建SpringBoot项目

2、导入依赖

<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.2</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>mybatis-plus-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>mybatis-plus-demo</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><!--根据实际数据库版本导入--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.20</version><scope>runtime</scope></dependency><!--此版本的spring boot test没引入junit,需要自己手动引入--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

3、配置

application.yml配置文件

spring:datasource:#mysql驱动6.0版本以上的为com.mysql.cj.jdbc.Driverdriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/testusername: rootpassword: root1234mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启SQL语句打印

4、数据库脚本

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@'),(2, 'Jack', 20, 'test2@'),(3, 'Tom', 28, 'test3@'),(4, 'Sandy', 21, 'test4@'),(5, 'Billie', 24, 'test5@');

5、编码

实体类:

package com.example.demo.po;import lombok.Data;/*** 〈实体类,类名和属性名需要符合驼峰命名法,可以不用关联表名,mybatis会自动关联〉<br>* 否则需要使用mybatis的@TableName,@TableId,@TableField等注解,将实体类和表关联*/@Datapublic class User {private Long id;private String name;private Integer age;private String email;}

mapper接口:

package com.example.demo.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.example.demo.po.User;public interface UserMapper extends BaseMapper<User> {}

service接口

package com.example.demo.service;import com.baomidou.mybatisplus.extension.service.IService;import com.example.demo.po.User;public interface UserService extends IService<User> {}

service实现类:

package com.example.demo.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.example.demo.mapper.UserMapper;import com.example.demo.po.User;import com.example.demo.service.UserService;import org.springframework.stereotype.Service;@Servicepublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}

Spring Boot 启动类:

package com.example.mybatisplusdemo;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication(scanBasePackages = "com.example")@MapperScan("com.example.demo.mapper")public class MybatisPlusDemoApplication {public static void main(String[] args) {SpringApplication.run(MybatisPlusDemoApplication.class, args);}}

测试类

package com.example.mybatisplusdemo;import com.example.demo.mapper.UserMapper;import com.example.demo.po.User;import com.example.demo.service.UserService;import org.junit.jupiter.api.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)@SpringBootTestclass MybatisPlusDemoApplicationTests {@Autowiredprivate UserMapper userMapper;@Autowiredprivate UserService userService;@Testvoid contextLoads() {List<User> userList = userMapper.selectList(null);userList.forEach(System.out::println);}@Testvoid test(){List<User> userList = userService.getBaseMapper().selectList(null);userList.forEach(System.out::println);}}

运行测试方法结果:

项目结构:

mp的service里定义了mapper,我们在service里使用mapper时无需注入,直接使用this.baseMapper即可。

二、核心功能

1、注解

@TableName

表名注解,标识实体类对应的表。如果类名使用驼峰命名法命名,可以不使用该注解。示例:ta_user表对应的实体类为taUser。或者表名与类名相同也无需使用该注解

@TableId

主键注解,用在主键字段上

IdType的值

@TableField

字段注解(非主键)

FieldStrategy

字段验证策略

FieldFill

字段填充策略

@Version

乐观锁注解、标记 @Verison 在字段上,作为版本号。

@EnumValue

普通枚举类注解(注解在枚举字段上)

@TableLogic

@KeySequence

序列主键策略 (oracle)

@OrderBy

内置 SQL 默认指定排序,优先级低于 wrapper 条件查询

@InterceptorIgnore

插件过滤规则

2、CRUD接口

mp封装了一些最基础的CRUD方法,只需要直接继承mp提供的接口,无需编写任何SQL,即可食用。mp提供了两套接口,分别是Mapper CRUD接口和Service CRUD接口。并且mp还提供了条件构造器Wrapper,可以方便地组装SQL语句中的WHERE条件。

Mapper CRUD接口

只需定义好实体类,然后创建一个接口,继承mp提供的BaseMapper,即可使用。mp会在mybatis启动时,自动解析实体类和表的映射关系,并注入带有通用CRUD方法的mapper。

部分方法示例:

insert(T entity) 插入一条记录deleteById(Serializable id) 根据主键id删除一条记录delete(Wrapper<T> wrapper) 根据条件构造器wrapper进行删除deleteByMap(Map<String, Object> columnMap) 根据多个列删除数据deleteBatchIds(Collection<?> idList) 根据主键id进行批量删除selectById(Serializable id) 根据主键id进行查找selectBatchIds(Collection idList) 根据主键id进行批量查找selectByMap(Map<String,Object> map) 根据map中指定的列名和列值进行等值匹配查找selectMaps(Wrapper<T> wrapper) 根据 wrapper 条件,查询记录,将查询结果封装为一个Map,Map的key为结果的列,value为值selectList(Wrapper<T> wrapper) 根据条件构造器wrapper进行查询selectOne(Wrapper<T> queryWrapper) 根据条件查找第一条记录update(T entity, Wrapper<T> wrapper) 根据条件构造器wrapper进行更新updateById(T entity) 根据id更新记录exists(Wrapper<T> queryWrapper) 根据条件查找是否存在记录selectCount(Wrapper<T> queryWrapper) 查询行数selectPage(P page, Wrapper<T> queryWrapper) 分页查询,结果是实体类selectMapsPage(P page, Wrapper<T> queryWrapper) 分页查询,结果是mapselectObjs(Wrapper<T> queryWrapper) 只查询第一列数据

Service CRUD 接口

另外一套CRUD是Service层的,只需要编写一个接口,继承IService,并创建一个接口实现类即可使用。这个接口提供的CRUD方法,和Mapper接口提供的功能大同小异,比较明显的区别在于IService支持了更多的批量化操作,如saveBatch,saveOrUpdateBatch等方法。

// 插入一条记录(选择字段,策略插入)boolean save(T entity);// 插入(批量)boolean saveBatch(Collection<T> entityList);// 插入(批量)boolean saveBatch(Collection<T> entityList, int batchSize);// TableId 注解存在更新记录,否插入一条记录boolean saveOrUpdate(T entity);// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);// 批量修改插入boolean saveOrUpdateBatch(Collection<T> entityList);// 批量修改插入boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);// 根据 entity 条件,删除记录boolean remove(Wrapper<T> queryWrapper);// 根据 ID 删除boolean removeById(Serializable id);// 根据 columnMap 条件,删除记录boolean removeByMap(Map<String, Object> columnMap);// 删除(根据ID 批量删除)boolean removeByIds(Collection<? extends Serializable> idList);// 根据 UpdateWrapper 条件,更新记录 需要设置sqlsetboolean update(Wrapper<T> updateWrapper);// 根据 whereWrapper 条件,更新记录boolean update(T updateEntity, Wrapper<T> whereWrapper);// 根据 ID 选择修改boolean updateById(T entity);// 根据ID 批量更新boolean updateBatchById(Collection<T> entityList);// 根据ID 批量更新boolean updateBatchById(Collection<T> entityList, int batchSize);// 根据 ID 查询T getById(Serializable id);// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")T getOne(Wrapper<T> queryWrapper);// 根据 Wrapper,查询一条记录T getOne(Wrapper<T> queryWrapper, boolean throwEx);// 根据 Wrapper,查询一条记录Map<String, Object> getMap(Wrapper<T> queryWrapper);// 根据 Wrapper,查询一条记录<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);// 无条件分页查询IPage<T> page(IPage<T> page);// 条件分页查询IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);// 无条件分页查询IPage<Map<String, Object>> pageMaps(IPage<T> page);// 条件分页查询IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);// 查询所有List<T> list();// 查询列表List<T> list(Wrapper<T> queryWrapper);// 查询(根据ID 批量查询)Collection<T> listByIds(Collection<? extends Serializable> idList);// 查询(根据 columnMap 条件)Collection<T> listByMap(Map<String, Object> columnMap);// 查询所有列表List<Map<String, Object>> listMaps();// 查询列表List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);// 查询全部记录List<Object> listObjs();// 查询全部记录<V> List<V> listObjs(Function<? super Object, V> mapper);// 根据 Wrapper 条件,查询全部记录List<Object> listObjs(Wrapper<T> queryWrapper);// 根据 Wrapper 条件,查询全部记录<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);// 查询总记录数int count();// 根据 Wrapper 条件,查询总记录数int count(Wrapper<T> queryWrapper);// 链式查询 普通QueryChainWrapper<T> query();// 链式查询 lambda 式。注意:不支持 KotlinLambdaQueryChainWrapper<T> lambdaQuery();// 链式更改 普通UpdateChainWrapper<T> update();// 链式更改 lambda 式。注意:不支持 KotlinLambdaUpdateChainWrapper<T> lambdaUpdate();

3、条件构造器

mp提供了强大的条件构造器Wrapper,条件构造器主要涉及到3个类,AbstractWrapper,QueryWrapper,UpdateWrapper。条件构造器也支持lambda表达式,使用LambdaQueryChainWrapper、LambdaUpdateChainWrapper。

在AbstractWrapper中提供了非常多的方法用于构建WHERE条件,而QueryWrapper针对SELECT语句,提供了select()方法,可自定义需要查询的列,而UpdateWrapper针对UPDATE语句,提供了set()方法,用于构造set语句。

AbstractWrapper中用于构建SQL语句中的WHERE条件的方法进行部分列举

eq:equals,等于allEq:all equals,全等于ne:not equals,不等于gt:greater than ,大于 >ge:greater than or equals,大于等于≥lt:less than,小于<le:less than or equals,小于等于≤between:相当于SQL中的BETWEENnotBetweenlike:模糊匹配。like("name","黄"),相当于SQL的name like '%黄%'likeRight:模糊匹配右半边。likeRight("name","黄"),相当于SQL的name like '黄%'likeLeft:模糊匹配左半边。likeLeft("name","黄"),相当于SQL的name like '%黄'notLike:notLike("name","黄"),相当于SQL的name not like '%黄%'isNullisNotNullinand:SQL连接符ANDor:SQL连接符ORapply:用于拼接SQL,该方法可用于数据库函数,并可以动态传参last:无视优化规则直接拼接到 sql 的最后

使用案例:

// 案例先展示需要完成的SQL语句,后展示Wrapper的写法 // 1. 名字中包含佳,且年龄小于25 // SELECT * FROM user WHERE name like '%佳%' AND age < 25 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.like("name", "佳").lt("age", 25); List<User> users = userMapper.selectList(wrapper); // 下面展示SQL时,仅展示WHERE条件;展示代码时, 仅展示Wrapper构建部分 // 2. 姓名为黄姓,且年龄大于等于20,小于等于40,且email字段不为空 // name like '黄%' AND age BETWEEN 20 AND 40 AND email is not null wrapper.likeRight("name","黄").between("age", 20, 40).isNotNull("email"); // 3. 姓名为黄姓,或者年龄大于等于40,按照年龄降序排列,年龄相同则按照id升序排列 // name like '黄%' OR age >= 40 order by age desc, id asc wrapper.likeRight("name","黄").or().ge("age",40).orderByDesc("age").orderByAsc("id"); // 4.创建日期为3月22日,并且直属上级的名字为李姓 // date_format(create_time,'%Y-%m-%d') = '-03-22' AND manager_id IN (SELECT id FROM user WHERE name like '李%') wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", "-03-22") // 建议采用{index}这种方式动态传参, 可防止SQL注入 .inSql("manager_id", "SELECT id FROM user WHERE name like '李%'"); // 上面的apply, 也可以直接使用下面这种方式做字符串拼接,但当这个日期是一个外部参数时,这种方式有SQL注入的风险 wrapper.apply("date_format(create_time, '%Y-%m-%d') = '-03-22'"); // 5. 名字为王姓,并且(年龄小于40,或者邮箱不为空) // name like '王%' AND (age < 40 OR email is not null) wrapper.likeRight("name", "王").and(q -> q.lt("age", 40).or().isNotNull("email")); // 6. 名字为王姓,或者(年龄小于40并且年龄大于20并且邮箱不为空) // name like '王%' OR (age < 40 AND age > 20 AND email is not null) wrapper.likeRight("name", "王").or( q -> q.lt("age",40) .gt("age",20) .isNotNull("email") ); // 7. (年龄小于40或者邮箱不为空) 并且名字为王姓 // (age < 40 OR email is not null) AND name like '王%' wrapper.nested(q -> q.lt("age", 40).or().isNotNull("email")) .likeRight("name", "王"); // 8. 年龄为30,31,34,35 // age IN (30,31,34,35) wrapper.in("age", Arrays.asList(30,31,34,35)); // 或 wrapper.inSql("age","30,31,34,35"); // 9. 年龄为30,31,34,35, 返回满足条件的第一条记录 // age IN (30,31,34,35) LIMIT 1 wrapper.in("age", Arrays.asList(30,31,34,35)).last("LIMIT 1"); // 10. 只选出id, name 列 (QueryWrapper 特有) // SELECT id, name FROM user; wrapper.select("id", "name"); // 11. 选出id, name, age, email, 等同于排除 manager_id 和 create_time // 当列特别多, 而只需要排除个别列时, 采用上面的方式可能需要写很多个列, 可以采用重载的select方法,指定需要排除的列 wrapper.select(User.class, info -> {String columnName = info.getColumn(); return !"create_time".equals(columnName) && !"manager_id".equals(columnName); });

Condition

条件构造器的诸多方法中,均可以指定一个boolean类型的参数condition,用来决定该条件是否加入最后生成的WHERE语句中,比如

String name = "黄"; // 假设name变量是一个外部传入的参数 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.like(StringUtils.hasText(name), "name", name); // 仅当 StringUtils.hasText(name) 为 true 时, 会拼接这个like语句到WHERE中 // 其实就是对下面代码的简化 if (StringUtils.hasText(name)) {wrapper.like("name", name); }

实体对象作为条件

调用构造函数创建一个Wrapper对象时,可以传入一个实体对象。后续使用这个Wrapper时,会以实体对象中的非空属性,构建WHERE条件(默认构建等值匹配的WHERE条件,这个行为可以通过实体类里各个字段上的@TableField注解中的condition属性进行改变)例如:@TableField(condition = SqlCondition.LIKE) // 配置该字段使用like进行拼接

SqlCondition类中预定义了一些字符串以供选择

package com.baomidou.mybatisplus.annotation; public class SqlCondition {//下面的字符串中, %s 是占位符, 第一个 %s 是列名, 第二个 %s 是列的值 public static final String EQUAL = "%s=#{%s}"; public static final String NOT_EQUAL = "%s&lt;&gt;#{%s}"; public static final String LIKE = "%s LIKE CONCAT('%%',#{%s},'%%')"; public static final String LIKE_LEFT = "%s LIKE CONCAT('%%',#{%s})"; public static final String LIKE_RIGHT = "%s LIKE CONCAT(#{%s},'%%')"; }

SqlCondition中提供的配置比较有限,有时需要自己拼接

例如:

@TableField(condition = “%s > #{%s}”) 表示大于

lambda条件构造器

lambda条件构造器,支持lambda表达式,可以不必像普通条件构造器一样,以字符串形式指定列名,它可以直接以实体类的方法引用来指定列。

LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.like(User::getName, "黄").lt(User::getAge, 30); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println);

lambda条件构造器可以链式调用,使代码更简洁

LambdaQueryChainWrapper<User> chainWrapper = new LambdaQueryChainWrapper<>(userMapper); List<User> users = chainWrapper.like(User::getName, "黄").gt(User::getAge, 30).list(); users.forEach(System.out::println);

三、代码示例

查询简单示例

@Testvoid selectTest(){//QueryWrapper查询List<User> userList = userService.getBaseMapper().selectList(new QueryWrapper<User>().eq("name","Jack"));userList.forEach(System.out::println);//LambdaQueryWrapper查询List<User> userList1 = userService.getBaseMapper().selectList(new LambdaQueryWrapper<User>().eq(User::getName,"Jack"));userList1.forEach(System.out::println);//LambdaQueryChainWrapper查询List<User> userList2 = userService.lambdaQuery().eq(User::getName,"Jack").list();userList2.forEach(System.out::println);}

update 简单示例

@Testvoid updateTest(){//UpdateWrapper更新boolean flag = userService.update(new UpdateWrapper<User>().eq("name","Jack").set("age",20));System.out.println(flag);//LambdaUpdateWrapper更新boolean flag1 = userService.update(new LambdaUpdateWrapper<User>().in(User::getId,new int[]{1,2}).set(User::getAge,18));System.out.println(flag1);boolean flag2 = userService.lambdaUpdate().in(User::getId,new String[]{"1","2"}).set(User::getAge,17).update();System.out.println(flag2);}

insert 简单示例:

@Testvoid insertTest(){User user1 = new User();user1.setId(6L);user1.setName("Mic");user1.setAge(29);user1.setEmail("test6@");int count = userMapper.insert(user1);System.out.println(count);User user2 = new User();user2.setId(7L);user2.setName("Sam");user2.setAge(23);user2.setEmail("test7@");boolean falg = userService.save(user2);System.out.println(falg);}

delete示例:

@Testvoid deleteTest(){int result = userMapper.delete(new QueryWrapper<User>().eq("id",6));System.out.println(result);int result2 = userMapper.delete(new LambdaQueryWrapper<User>().eq(User::getId,7));System.out.println(result);}

分页查询示例

mp使用分页查询前,需要先把分页查询查插件注册到spring中

package com.example.demo.config;import com.baomidou.mybatisplus.annotation.DbType;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class MybatisPlusConfig {/** 新版mp **/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}/** 旧版mp 用 PaginationInterceptor **/}

分页查询示例:

@Testvoid selectpageTest(){//QueryWrapper查询IPage<User> pageList = userService.getBaseMapper().selectPage(new Page<User>(0,2),new QueryWrapper<User>());List<User> userList = pageList.getRecords();userList.forEach(System.out::println);IPage<User> pageList1 = userService.getBaseMapper().selectPage(new Page<User>(0,2),new LambdaQueryWrapper<User>());List<User> userList1 = pageList1.getRecords();userList1.forEach(System.out::println);IPage<User> pageList2 = userService.lambdaQuery().page(new Page<User>(0,2));List<User> userList2 = pageList2.getRecords();userList2.forEach(System.out::println);

分页查询默认会先查count总条数,如果不希望查count,可以通过Page的重载构造函数,指定isSearchCount为false即可

public Page(long current, long size, boolean isSearchCount)

使用mybatis原生的方式做查询时,如果需要使用分页,可以在接口上加上page参数:Param(“page”) Page<> page,即可使用分页方法,而无需在sql中写分页语句

四、总结

mp在mybatis的基础上做了增强,提供许多简单的CRUD方法,我们拿来直接用即可。而且mp也保留了原生的mybatis的功能,我们也可以使用原生的在mapper.xml中写sql的方式执行crud。本文只是介绍了mybatis-plus的基础功能,方便新手快速入门,mybatis-plus还有许多有趣的功能,可以自行去官网查阅。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。