MyBatisPlus
快速入门
1.创建数据库mybatisplus
2.创建user表并插入数据
- 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)
- );
- 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');
- -- 真实开发中一般还需要version(乐观锁)、deleted(逻辑删除)、gmt_create、gmt_modified
复制代码 3.初始化SpringBoot项目
4.导入依赖
尽量不要同时导入mybatis和mybatisplus的依赖
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- </dependency>
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>mybatis-plus-boot-starter</artifactId>
- <version>3.0.5</version>
- </dependency>
复制代码 5.连接数据库
application.properties- # mysql 5 驱动不同 com.mysql.jdbc.Driver
- # mysql 8 驱动不同com.mysql.cj.jdbc.Driver、需要增加时区的配置serverTimezone=GMT%2B8
- spring.datasource.username=root
- spring.datasource.password=123456
- spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
- spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
复制代码 6.传统方式pojo-dao(连接mybatis,配置mapper.xml文件)-service-controller
6.使用MyBatisPlus
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- public class User {
- private Long id;
- private String name;
- private Integer age;
- private String email;
- }
复制代码- @Repository//持久层
- public interface UserMapper extends BaseMapper<User> {
- }
复制代码首先在主类中配置mapper扫描@MapperScan("com.xust.mapper")
- @SpringBootTest
- class MybatisPlusApplicationTests {
- @Autowired
- private UserMapper userMapper;
- @Test
- void contextLoads() {
- //参数是一个Wrapper,条件构造器,这里先不用
- List<User> users=userMapper.selectList(null);
- users.forEach(System.out::println);
- }
- }
复制代码 配置日志
在开发中使用,通过日志查看sql如何执行
applicatiohn.properties- mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
复制代码 CRUD扩展
插入
- @SpringBootTest
- class MybatisPlusApplicationTests {
- // 测试插入
- @Test
- public void testInsert() {
- User user = new User();
- user.setName("xust");
- user.setAge(3);
- user.setEmail("24736743@qq.com");
- int result = userMapper.insert(user); // 帮我们自动生成id
- System.out.println(result); // 受影响的行数
- System.out.println(user); // 发现,id会自动回填
- }
- }
复制代码 更新
- @SpringBootTest
- class MybatisPlusApplicationTests {
- @Autowired
- private UserMapper userMapper;
- //测试更新
- @Test
- public void testUpdate(){
- User user = new User();
- user.setId(1L);
- user.setName("xxx");
- userMapper.updateById(user);
- }
- }
复制代码 自动填充
创建时间、修改时间!这些个操作一遍都是自动化完成的,我们不希望手动更新
我这里使用的是SQLyog
数据库级别操作

代码级别操作
1.首先恢复清除数据库中默认值和更新效果
2.实体类字段属性上需要增加注解- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- public class User {
- @TableId(type = IdType.INPUT) //一旦手动输入id后就需要自己配置id了
- private Long id;
- private String name;
- private Integer age;
- private String email;
- @TableField(fill= FieldFill.INSERT) //插入时自动填充
- private Date createTime;
- @TableField(fill= FieldFill.INSERT_UPDATE) //插入和更新时自动填充
- private Date updateTime;
- }
复制代码 3.编写处理器来处理这个注解- @Slf4j
- @Component //将处理器加入到IOC容器中
- public class MyMetaObjectHandler implements MetaObjectHandler {
- //插入时的填充策略
- @Override
- public void insertFill(MetaObject metaObject) {
- log.info("start insert fill...........");
- this.setFieldValByName("createTime",new Date(),metaObject);
- this.setFieldValByName("updateTime",new Date(),metaObject);
- }
- //更新时的填充策略
- @Override
- public void updateFill(MetaObject metaObject) {
- log.info("start update fill...........");
- this.setFieldValByName("updateTime",new Date(),metaObject);
- }
- }
复制代码 乐观锁
意图:
当更新一条数据时,希望这条数据没有被其他人更新。
- 乐观锁:它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,再次更新值测试
- 悲观锁:它总是认为总是出现问题,无论干什么都会上锁!再去操作
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时带上version
- 执行更新时,set version=newVersion where version=oldVersion
- 如果version不对,就更新失败
- 乐观锁:1、先查询,获得版本号 version = 1
- -- A
- update user set name = "kuangshen", version = version + 1
- where id = 2 and version = 1
- -- B 线程抢先完成,这个时候 version = 2,会导致 A 修改失败!
- update user set name = "kuangshen", version = version + 1
- where id = 2 and version = 1
复制代码 测试
1. 数据库添加version字段

2.实体类加对应字段
- @Version //乐观锁Version注解
- private Integer version;
复制代码 3.注册组件
- @EnableTransactionManagement
- @Configuration // 配置类
- public class MyBatisPlusConfig { // 注册乐观锁插件
- @Bean
- public OptimisticLockerInterceptor optimisticLockerInterceptor() {
- return new OptimisticLockerInterceptor();
- }
- }
复制代码 4.测试
- @SpringBootTest
- class MybatisPlusApplicationTests {
- @Autowired
- private UserMapper userMapper;
- //测试乐观锁成功
- @Test
- public void testOptimisticLocker(){
- //查询用户信息
- User user = userMapper.selectById(1L);
- //修改用户信息
- user.setName("yyy");
- user.setEmail("111@qq.com");
- //执行更新操作
- userMapper.updateById(user);
- }
- //测试乐观锁失败
- @Test
- public void testOptimisticLocker2(){
- //A
- User user = userMapper.selectById(1L);
- user.setName("yyy1");
- user.setEmail("123@qq.com");
- //B,模拟另外一个线程执行了插队操作
- User user2 = userMapper.selectById(1L);
- user2.setName("yyy2");
- user2.setEmail("222@qq.com");
- //B执行更新
- userMapper.updateById(user2);
- //A执行更新,如果没有乐观锁就会更新
- userMapper.updateById(user);
- }
- }
复制代码 查询操作
- @SpringBootTest
- class MybatisPlusApplicationTests {
- @Autowired
- private UserMapper userMapper;
- // 测试查询
- @Test
- public void testSelectById() {
- User user = userMapper.selectById(1L);
- System.out.println(user);
- }
- // 测试批量查询!
- @Test
- public void testSelectByBatchId() {
- List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
- users.forEach(System.out::println);
- }
- // 按条件查询之使用map操作
- @Test
- public void testSelectByBatchIds() {
- HashMap<String, Object> map = new HashMap<>();
- // 自定义要查询
- map.put("name", "ccc");
- map.put("age", 3);
- List<User> users = userMapper.selectByMap(map);
- users.forEach(System.out::println);
- }
- }
复制代码 分页查询
1.配置拦截器组件
MyBatisPlusConfig.java- @Bean
- public PaginationInterceptor paginationInterceptor() {
- return new PaginationInterceptor();
- }
复制代码 2.直接使用Page对象
- @SpringBootTest
- class MybatisPlusApplicationTests {
- @Autowired
- private UserMapper userMapper;
- //测试分页查询
- @Test
- public void testPage(){
- //参数一:当前页
- //参数二:显示条数
- Page<User> page=new Page<>(1,3);
- userMapper.selectPage(page,null);
- //打印当前页
- page.getRecords().forEach(System.out::println);
- //打印总数
- System.out.println(page.getTotal());
- }
- }
复制代码 删除操作
根据id删除
- @SpringBootTest
- class MybatisPlusApplicationTests {
- @Autowired
- private UserMapper userMapper;
- //测试删除
- @Test
- public void testDeleteById() {
- userMapper.deleteById(1579436224978829314L);
- }
- //批量删除
- @Test
- public void testDeleteBatchId() {
- userMapper.deleteBatchIds(Arrays.asList(1579459015811768322L, 1579459015811768324L));
- }
- //条件删除map操作
- @Test
- public void testDeleteMap() {
- HashMap<String, Object> map = new HashMap<>();
- map.put("name", "ccc");
- userMapper.deleteByMap(map);
- }
- }
复制代码 逻辑删除
物理删除:从数据库中直接移除
逻辑删除:在数据库中没有直接移除,通过一个变量使其失效
1.在数据库表中增加一个deleted字段,为0表示没删

2.实体类中增加属性
- @TableLogic //逻辑删除
- private Integer deleted;
复制代码 3.配置
MyBatisPlusConfig.java- // 逻辑删除组件!
- @Bean
- public ISqlInjector sqlInjector() {
- return new LogicSqlInjector();
- }
复制代码 application.properties- # 配置逻辑删除
- mybatis-plus.global-config.db-config.logic-delete-value=1
- mybatis-plus.global-config.db-config.logic-not-delete-value=0
复制代码 4.测试
执行之前的删除操作,实际上进行的是update操作
性能分析插件
平时开发时会遇到一些慢SQL
作用:性能分析拦截器,用于输出每条 SQL 语句及其执行时间
在测试和开发环境下使用
1.设置开发环境
application.properties- spring.profiles.active=dev
复制代码 2.导入插件
MyBatisPlusConfig.java- @Bean
- @Profile({"dev","test"}) //设置在dev、test环境开启,保证效率
- public PerformanceInterceptor performanceInterceptor(){
- PerformanceInterceptor performanceInterceptor=new PerformanceInterceptor();
- performanceInterceptor.setMaxTime(100); //设置SQL执行的最大时间,超过则不执行
- performanceInterceptor.setFormat(true); //是否开启格式化,让SQL查看起来更方便
- return performanceInterceptor;
- }
复制代码 条件构造器(Wrapper)
比较重要,写复杂的SQL可以用它来代替
[code]@SpringBootTestpublic class WrapperTest { @Autowired private UserMapper userMapper; @Test void contextLoads() { //查询name不为空,email不为空,且年龄大于等于12的 QueryWrapper wrapper=new QueryWrapper(); wrapper.isNotNull("name") .isNotNull("email") .ge("age",12); userMapper.selectList(wrapper); } @Test void test2() { //查询name为Tom的 QueryWrapper wrapper=new QueryWrapper(); wrapper.eq("name","Tom"); User user = userMapper.selectOne(wrapper); System.out.println(user); } @Test void test3() { //查询年龄20~30的人 QueryWrapper wrapper=new QueryWrapper(); wrapper.between("age",20,30); Integer count= userMapper.selectCount(wrapper);//查询结果数 System.out.println(count); } //模糊查询 @Test void test4() { //name中不包含o,且email以t开头 QueryWrapper wrapper=new QueryWrapper(); wrapper.notLike("name","o") .likeRight("email","t"); //相当于t% List maps= userMapper.selectMaps(wrapper); maps.forEach(System.out::println); } @Test void test5() { QueryWrapper wrapper=new QueryWrapper(); //id在子查询中查出来 wrapper.inSql("id","select id from user where id |