Mybatis-plus快速入门与详解

一、MyBatis-Plus简介

1、简介

MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为 简化开发、提高效率而生。

我们的愿景是成为 MyBatis 最好的搭档,就像魂斗罗中的 1P、2P,基友搭配,效率翻倍。

image-20220518205901937.png
2、特性
  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
3、支持数据库

任何能使用 MyBatis 进行 CRUD, 并且支持标准 SQL 的数据库,具体支持情况如下,如果不在下列表查看分页部分教程 PR 您的支持。

  • MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb
  • 达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库
4、框架结构
image-20220518210026312.png
5、代码及文档地址

官方地址: http://mp.baomidou.com

代码发布地址:

文档发布地址: https://baomidou.com/pages/24112f

二、入门案例

1、建表

我们使用Mysql8版本

创建表

CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
use `mybatis_plus`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL COMMENT '主键ID',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

添加数据

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');
2、导入依赖
<dependency>
     <groupId>com.baomidou</groupId>
     <artifactId>mybatis-plus-boot-starter</artifactId>
     <version>3.5.1</version>
</dependency>
<dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
     <optional>true</optional>
</dependency>
<dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <scope>runtime</scope>
</dependency>

其中,lombok只是为了简化我们实体类的代码

IDEA 2020.3及以上版本已经内置Lombok plugin了,无需安装插件

3、application.yml
spring:
  # 配置数据源信息
  datasource:
  # 配置数据源类型
    type: com.zaxxer.hikari.HikariDataSource
    # 配置连接数据库信息
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3307/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
    username: root
    password: root

#配置mybatis日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  # 配置MyBatis-Plus操作表的默认前缀
  global-config:
    db-config:
      table-prefix: t_
      # 配置MyBatis-Plus的主键策略
#      id-type: auto
  # 配置类型别名所对应的包
#  type-aliases-package: com.zl.po
4、启动类

在Spring Boot启动类中添加@MapperScan注解,扫描mapper包

package com.zl;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


/**
 * @date 2022-05-15
 * @author ZL
 */
@SpringBootApplication
@MapperScan("com.zl.mapper")
public class MybatisPlusDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusDemoApplication.class, args);
    }

}
5、实体类
package com.zl.po;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author zl
 * @time 2022/5/15
 */
@Data
@TableName("t_user")
public class User {

    //@TableId("uid")
    private Long id;

    //@TableField("user_name")
    private String name;

    private Integer age;

    private String email;

    /**
     * 逻辑删除
     */
    //@TableLogic
   // private Integer isDeleted;
}
6、通用Mapper接口
package com.zl.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zl.po.User;
import org.springframework.stereotype.Repository;

/**
 * @author zl
 * @time 2022/5/15
 */
@Repository
public interface UserMapper extends BaseMapper<User> {

}
7、测试
package com.zl;

import com.zl.mapper.UserMapper;
import com.zl.po.User;
import com.zl.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.*;

/**
 * 通用Mapper测试
 */
@SpringBootTest
class MybatisPlusTest {

    @Autowired
    private UserMapper userMapper;

    /**
     * 查询所有
     * SELECT id,name,age,email FROM user
     */
    @Test
    void testSelectList() {
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

三、进阶

1、不同数据库yml配置

Mysql

spring:
  # 配置数据源信息
  datasource:
  # 配置数据源类型
    type: com.zaxxer.hikari.HikariDataSource
    # 配置连接数据库信息
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3307/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
    username: root
    password: root

#配置mybatis日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  # 配置MyBatis-Plus操作表的默认前缀
  global-config:
    db-config:
      table-prefix: t_
      # 配置MyBatis-Plus的主键策略
#      id-type: auto
  # 配置类型别名所对应的包
#  type-aliases-package: com.zl.po

其中mysql8的url为:

jdbc:mysql://localhost:3307/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false

mysql5的url为:

jdbc:mysql://localhost:3307/mybatis_plus?characterEncoding=utf-8&useSSL=false

Sqlserver

# DataSource Config
spring:
  datasource:
    username: sa
    password: root
    url: jdbc:sqlserver://localhost:1433;DatabaseName=test
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver

Oracle

spring:
  datasource:
    driverClassName: oracle.jdbc.OracleDriver
    username: root
    password: root
    url: jdbc:oracle:thin:@//localhost:1521/test
2、通用Service接口

Uservice

package com.zl.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zl.po.User;

/**
 * @author zl
 * @time 2022/5/15
 */
public interface UserService extends IService<User> {
}

UserServiceImpl

package com.zl.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zl.mapper.UserMapper;
import com.zl.po.User;
import com.zl.service.UserService;
import org.springframework.stereotype.Service;

/**
 * @author zl
 * @time 2022/5/15
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
3、通用Mapper和通用Service常规用法
package com.zl;

import com.zl.mapper.UserMapper;
import com.zl.po.User;
import com.zl.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.*;

/**
 * 通用Mapper测试
 */
@SpringBootTest
class MybatisPlusTest {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserService userService;

    
    /**
     * 查询所有
     * SELECT id,name,age,email FROM user
     */
    @Test
    void testSelectList() {
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }

    /**
     * 插入
     * INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
     */
    @Test
    void testInsert(){
        User user = new User();
        user.setName("张三");
        user.setAge(23);
        user.setEmail("zhangsan@163.com");
        int result = userMapper.insert(user);
        System.out.println("受影响的行数:"+result);
        System.out.println("新建的ID:"+user.getId());
    }

    /**
     * 根据ID删除
     * DELETE FROM user WHERE id=?
     */
    @Test
    void testDeleteById(){
        int result = userMapper.deleteById(1525835539440345090L);
        System.out.println("受影响的行数:"+result);
    }


    /**
     * 根据ID批量删除
     * DELETE FROM user WHERE id IN ( ? , ? )
     */
    @Test
    void testDeleteBatchIds(){
        int result = userMapper.deleteBatchIds(Arrays.asList(1L, 2L));
        System.out.println("受影响的行数:"+result);
    }


    /**
     * 根据Map删除
     * DELETE FROM user WHERE name = ? AND age = ?
     */
    @Test
    void testDeleteByMap(){
        Map<String,Object> map = new HashMap<>();
        map.put("age",21);
        map.put("name","Sandy");
        int result = userMapper.deleteByMap(map);
        System.out.println("受影响的行数:"+result);
    }


    /**
     * 根据ID更新
     * UPDATE user SET name=?, age=? WHERE id=?
     */
    @Test
    void testUpdateById(){
        User user = new User();
        user.setId(5L);
        user.setName("admin");
        user.setAge(33);

        int result = userMapper.updateById(user);
        System.out.println("受影响的行数:"+result);
    }


    /**
     * 根据ID查询
     * SELECT id,name,age,email FROM user WHERE id=?
     */
    @Test
    void testSelectById(){
        User user = userMapper.selectById(5L);
        System.out.println(user);
    }


    /**
     * 根据ID批量查询
     * SELECT id,name,age,email FROM user WHERE id IN ( ? , ? )
     */
    @Test
    void testSelectByBatchIds(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(3L, 5L));
        users.forEach(System.out::println);
    }


    /**
     * 根据Map查询
     * SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
     */
    @Test
    void testSelectByMap(){
        Map<String,Object> map = new HashMap<>();
        map.put("name","admin");
        map.put("age",33);
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }

    /**
     * 查询总记录数
     * SELECT COUNT( * ) FROM user
     */
    @Test
    void testGetCount(){
        long count = userService.count();
        System.out.println("总记录数:"+count);
    }


    /**
     * 批量插入:执行10次
     * INSERT INTO user ( id, name, age ) VALUES ( ?, ?, ? )
     */
    @Test
    void testSaveBatch(){
        List<User> userList = new ArrayList<>();
        for (int i=0;i<10;i++){
            User user = new User();
            user.setName("zl" + i);
            user.setAge(20 + i);
            userList.add(user);
        }

        boolean flag = userService.saveBatch(userList);
        System.out.println("插入是否成功:"+flag);
    }
}
4、Wrapper常规用法
package com.zl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.zl.mapper.UserMapper;
import com.zl.po.User;
import com.zl.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;

/**
 * Wrapper测试
 * @author zl
 * @time 2022/5/15
 */
@SpringBootTest
public class MybatisPlusWrapperTest {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserService userService;


    /**
     * 查询用户名包含a,年龄在20到30之间,并且邮箱不为null的用户信息
     * SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
     */
    @Test
    void test01(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("user_name","a")
                .between("age",20,30)
                .isNotNull("email");
        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);
    }


    /**
     * 按年龄降序查询用户,如果年龄相同则按id升序排列
     * SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASC
     */
    @Test
    void test02(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("age").orderByAsc("uid");
        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);
    }


    /**
     * 删除email为空的用户
     * UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)
     */
    @Test
    void test03(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int result = userMapper.delete(queryWrapper);
        System.out.println("影响的行数:"+result);
    }


    /**
     * 将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改
     * UPDATE t_user SET age=?, email=? WHERE is_deleted=0 AND (age >= ? AND user_name LIKE ? OR email IS NULL)
     */
    @Test
    void test04(){
        User user = new User();
        user.setAge(10);
        user.setEmail("zl@163.com");

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.ge("age",20)
                .like("user_name","a")
                .or()
                .isNull("email");

        int result = userMapper.update(user, queryWrapper);
        System.out.println("受影响的行数:"+result);
    }


    /**
     * 将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
     * UPDATE t_user SET age=?, email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age >= ? OR email IS NULL))
     */
    @Test
    void test05(){
        User user = new User();
        user.setAge(15);
        user.setEmail("zl2@163.com");

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("user_name","a")
                .and(i->i.ge("age",20).or().isNull("email"));

        int result = userMapper.update(user, queryWrapper);
        System.out.println("受影响的行数:"+result);
    }

    //todo 组装select子句


    /**
     * 查询用户信息的username和age字段
     * SELECT user_name,age FROM t_user WHERE is_deleted=0
     */
    @Test
    void test06(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("user_name","age");

        //selectMaps()返回Map集合列表,通常配合select()使用,避免User对象中没有被查询到的列值为null
        List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
        maps.forEach(System.out::println);
    }


    /**
     * 将(年龄大于20或邮箱为null)并且用户名中包含有a的用户信息修改
     * UPDATE t_user SET age=?,email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
     */
    @Test
    void test07(){
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("age",18)
                .set("email","zl@163.com")
                .like("user_name","a")
                .and(i->i.gt("age",20).or().isNull("email"));

        int result = userMapper.update(null, updateWrapper);
        System.out.println("影响行数:"+result);
    }


    /**
     * Condition条件
     * SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (age >= ? AND age <= ?)
     */
    @Test
    void test08(){
        //定义查询条件,有可能为null(用户未输入或未选择)
        String username = null;
        Integer ageBegin = 10;
        Integer ageEnd = 24;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(username), "username", "a")
                .ge(ageBegin != null, "age", ageBegin)
                .le(ageEnd != null, "age", ageEnd);

        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);
    }



    @Test
    public void test09() {
        //定义查询条件,有可能为null(用户未输入)
        String username = "a";
        Integer ageBegin = 10;
        Integer ageEnd = 24;
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        //避免使用字符串表示字段,防止运行时错误
        queryWrapper
                .like(StringUtils.isNotBlank(username), User::getName, username)
                .ge(ageBegin != null, User::getAge, ageBegin)
                .le(ageEnd != null, User::getAge, ageEnd);
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }



    @Test
    public void test10() {
        //组装set子句
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .set(User::getAge, 18)
                .set(User::getEmail, "user@atguigu.com")
                .like(User::getName, "a")
                .and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail));
        //lambda表达式内的逻辑优先运算
        User user = new User();
        int result = userMapper.update(user, updateWrapper);
        System.out.println("受影响的行数:" + result);
    }
}
5、分页和乐观锁
1) 分页

配置类-包含分页和乐观锁

package com.zl.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 插件配置类-包含分页插件、乐观锁
 * @author zl
 * @time 2022/5/16
 */
@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //添加分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

简单测试--查询所有

/**
     * 分页
     * SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 LIMIT ?,?
     */
    @Test
    void testPage(){
        //当前页、每页显示条数
        Page<User> page = new Page<>(1,2);
        userMapper.selectPage(page, null);

        //获取分页数据
        List<User> list = page.getRecords();
        list.forEach(System.out::println);
        System.out.println("当前页:"+page.getCurrent());
        System.out.println("每页显示的条数:"+page.getSize());
        System.out.println("总记录数:"+page.getTotal());
        System.out.println("总页数:"+page.getPages());
        System.out.println("是否有上一页:"+page.hasPrevious());
        System.out.println("是否有下一页:"+page.hasNext());
    }

自定义分页接口

Mapper

/**
* 根据年龄查询用户列表,分页显示
* @param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位
* @param age 年龄
* @return
*/
Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);

UserMapper.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.zl.mapper.UserMapper">

    <!--  当实体类的属性名称和数据库的列名不一致时,需要用resultMap映射   -->
    <resultMap id="UserMap" type="User">
        <!-- id为主键 -->
        <id column="id" property="id"/>
        <!-- column是数据库表的列名 , property是对应实体类的属性名 -->
        <result column="uid" property="id"/>
        <result column="user_name" property="name"/>
    </resultMap>

    <!--Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);-->
    <select id="selectPageVo" resultMap="UserMap">
        select uid,user_name,age,email from t_user where age > #{age}
    </select>

</mapper>

测试类

    /**
     *
     * 自定义分页接口
     */
    @Test
    public void testSelectPageVo(){
        //设置分页参数
        Page<User> page = new Page<>(1, 2);
        userMapper.selectPageVo(page, 10);
        //获取分页数据
        List<User> list = page.getRecords();
        list.forEach(System.out::println);
        System.out.println("当前页:"+page.getCurrent());
        System.out.println("每页显示的条数:"+page.getSize());
        System.out.println("总记录数:"+page.getTotal());
        System.out.println("总页数:"+page.getPages());
        System.out.println("是否有上一页:"+page.hasPrevious());
        System.out.println("是否有下一页:"+page.hasNext());
    }
2) 乐观锁

数据库表要增加一个字段version

然后用注解@Version

package com.zl.po;

import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;

/**
 * @author zl
 * @time 2022/5/16
 */
@Data
public class Product {

    private Long id;
    private String name;
    private Integer price;

    @Version
    private Integer version;
}

测试代码

/**
 * 乐观锁
 */
@Test
public void testProduct01(){
    //小李查询商品价格
    Product productLi = productMapper.selectById(1);
    System.out.println("小李查询的商品价格:"+productLi.getPrice());
    //小王查询商品价格
    Product productWang = productMapper.selectById(1);
    System.out.println("小王查询的商品价格:"+productWang.getPrice());
    //小李将商品价格+50
    productLi.setPrice(productLi.getPrice()+50);
    productMapper.updateById(productLi);
    //小王将商品价格-30
    productWang.setPrice(productWang.getPrice()-30);
    int result = productMapper.updateById(productWang);
    if(result == 0){
        //操作失败,重试
        Product productNew = productMapper.selectById(1);
        productNew.setPrice(productNew.getPrice()-30);
        productMapper.updateById(productNew);
    }
    //老板查询商品价格
    Product productLaoban = productMapper.selectById(1);
    System.out.println("老板查询的商品价格:"+productLaoban.getPrice());
}
6、代码生成器

依赖

<!--   代码生成器  -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.1</version>
</dependency>
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>

测试类

package com.zl;

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Collections;

/**
 * @author zl
 * @time 2022/5/16
 */
public class FastAutoGeneratorTest {

    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3307/mybatis_plus?characterEncoding=utf-8&userSSL=false", "root", "root")
                .globalConfig(builder -> {
                    builder.author("zl") // 设置作者
                            //.enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir("D://mybatis_plus"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.zl") // 设置父包名
                            .moduleName("mybatisplus") // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude("t_user") // 设置需要生成的表名
                            .addTablePrefix("t_", "c_"); // 设置过滤表前缀
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();
    }
}
7、多数据源

依赖

<!--   多数据源  -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.5.0</version>
</dependency>

配置文件

spring:
  # 配置数据源信息
  datasource:
    dynamic:
      # 设置默认的数据源或者数据源组,默认值即为master
      primary: master
      # 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源
      strict: false
      datasource:
        master:
          url: jdbc:mysql://localhost:3307/mybatis_plus?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: root
        slave_1:
          url: jdbc:mysql://localhost:3307/mybatis_plus_1?characterEncoding=utf-8&useSSL=false
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: root
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  type-aliases-package: com.zl.po

在UserServiceImpl上加上注解@DS

package com.zl.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zl.mapper.UserMapper;
import com.zl.po.User;
import com.zl.service.UserService;
import org.springframework.stereotype.Service;

/**
 * @author zl
 * @time 2022/5/15
 */
//指定所操作的数据源
@DS("master") 
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
8、MybatisX插件

MyBatis-Plus为我们提供了强大的mapper和service模板,能够大大的提高开发效率

但是在真正开发过程中,MyBatis-Plus并不能为我们解决所有问题,例如一些复杂的SQL,多表 联查,我们就需要自己去编写代码和SQL语句,我们该如何快速的解决这个问题呢,这个时候可 以使用MyBatisX插件 MyBatisX一款基于 IDEA 的快速开发插件,为效率而生。

MyBatisX插件用法:https://baomidou.com/pages/ba5b24

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342