Mybatisplus

在这里插入图片描述

MyBatis-Plus简介

MyBaits-Plus 是一个MyBatis增强工具,在MyBatis的基础上只做增强不做改变为简化开发、提高效率而生
MyBatis-Plus提供了通用的mapper和service,可以在不编写任何SQL语句的情况下,快速的实现对单表的CRUD、批量、逻辑删除、分页等操作

官方地址:https://baomidou.com/

MyBaits-Plus特性

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

支持数据库

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

MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb、达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库

框架结构

在这里插入图片描述
scan Entity: 扫描实体,表由实体类决定,然后通过反射技术将我们的实体类进行抽取,
在根据相应的方法(insert、update、delete、select),生成相应的sql语句,然后注入到容器中。

代码及文档地址

官方地址:http://mp.baomidou.com
代码发布地址:
Github:https://github.com/baomidou/mybatis-plus
Gitee:https://gitee.com/baomidou/mybaits-plus
文档发布地址:https://baomidou.com/pages/24112f

入门案例

  1. 开发环境
    IDE: idea 2019.2
    JDK: JDK8+
    构建工具:maven 3.5.4
    MySQL版本:MySQL5.7
    Spring Boot: 2.6.3
    MyBatis-Plus: 3.5.1
  2. 创建数据库及表
//创建数据库
create database mybatis_plus;
//创建表结构
create table user (
 id bigint(20) not null primary key comment '主键ID',
 name varchar(20) default null   comment '姓名',
 age int(11) default null comment '年龄',
 email varchar(50) default null comment '邮箱'
)
//插入数据
insert into user
values(1, 'Jone', 18, '111@qq.com'),
(2, 'Jack', 18, '11122@qq.com'),
(3, 'Tom', 20, '11133@qq.com'),
(4, 'Sandy', 21, '11144@qq.com'),
(5, 'Gille', 24, '11155@qq.com');
commit;
  1. 目录结构以及配置如下
    创建Mapper文件、User实体类、application.yml文件以及相应的测试方法
    在这里插入图片描述
    在这里插入图片描述
  2. UserMapper代码如
/**
 * mybatis-plus
 * 提供了通用的mapper和service
 * 1. 需要继承BaseMapper类
 * 2. BaseMapper包含了对单表 增、删、改、查的各种方法
 */
@Repository
public interface UserMapper extends BaseMapper<User> {

    /**
     * 根据id查询用户信息为map集合
     * @param id
     * @return
     */
    Map<String, Object> selectMapById(Long id);

    //分页插件作用于我们自定义的分页时,第一个参数必须是Page
    //@param相当于mapper.xml中的parameterType传递参数
    /**
     * 通过年龄查询用户信息并分页
     * @param page mybatis-plus提供的分页参数,必须第一个位置
     * @param age
     * @return
     */
  //  Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);
      Page<User> selectPageVo( Page<User> page,  Integer age);
}

  1. User
/**
 * @NoArgsConstructor
 * @AllArgsConstructor
 * @Setter
 * @Getter
 * @EqualsAndHashCode
 */
@Data
@Accessors(chain = true)
@TableName("t_user")
public class User {

  /*   @TableId
    private Long uid; //数据库bigint*/
    @TableId(value = "uid")
    private Long id;

    private String name; //用户名

    private Integer age; //年龄

    private String email; //邮箱

    private SexEnum sex;
}
  1. MybatisplusDemoApplication
@SpringBootApplication
public class MybatisplusDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisplusDemoApplication.class, args);
    }
}
  1. application.yml
#配置端口信息
server:
  port: 8084

#数据源 spring boot中默认所使用的数据源
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    # mysql是5版本可以使用这个,建议使用8版本
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
    #mysql 5 版本按照以下配置即可
    #url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false
    url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false&serverTimezone=GMT


# 配置mybatis_plus打印日志
mybatis-plus:
 #global-config:
 #   db-config:
 #     table-prefix: t_   #设置全局表的前缀
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:/mapper/**/*.xml     #默认位置
  #配置类型别名,不区分大小写
  type-aliases-package: com.cjw.mybatisplus.mybatisplusdemo.pojo
  #扫描通用枚举的包
  type-enums-package: com.cjw.mybatisplus.mybatisplusdemo.enums
  1. MybatisPlusTest
package com.cjw.mybatisplus.mybatisplusdemo;
import com.cjw.mybatisplus.mybatisplusdemo.mapper.UserMapper;
import com.cjw.mybatisplus.mybatisplusdemo.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class MybatisPlusTest {
    /**
     * userMapper为什么爆红?
     * 1、ioc只能存在类所对应的bean,不能存在接口所对应的bean
     * 2、ioc默认是将bean 进行装配的
     * 但是我们定义的是一个接口,导致可能无法装配,但是在
     * 运行的时候可以装配的
     * 3.可以在UserMapper中配置@Repository
     */
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testSelectList() {
        //List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
        /**
         * Wrapper是条件构造器
         * */
        //通过条件构造器来查询一个list集合,若没有集合,则可设置null
        List<User> list = userMapper.selectList(null);
        list.forEach(System.out::println);
    }
}
  1. pom.xml
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--mybaits-plus驱动-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <!--lombok简化实体类开发-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
        </dependency>
    </dependencies>
  1. Mybatisplusconfig
@Configuration
/**
 * 在springboot 使用mybatis需要
 * 设置mapper接口和映射文件所在的包
 */
@MapperScan("com.cjw.mybatisplus.mybatisplusdemo.mapper")
public class Mybatisplusconfig {

   @Bean
    public MybatisPlusInterceptor  mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
    //等价于

   /* *//**
     * 添加分页插件
     * @return
     *//*
    @Bean
    public PaginationInnerInterceptor paginationInnerInterceptor() {
        return new PaginationInnerInterceptor();
    }

    *//**
     * 添加乐观锁插件
     * @return
     *//*
    @Bean
    public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
        return new OptimisticLockerInnerInterceptor();
    }*/
}
  1. SexEnum
/**
 * 枚举作为取值使用
 * 因此使用Getter
 */
@Getter
public enum SexEnum {

     MALE(1, "男"),
     FEMALE(2, "女");

     @EnumValue //将注解所标识的属性的值注入到数据库中
    private Integer sex;
    private String sexName;

    SexEnum(Integer sex, String sexName) {
        this.sex = sex;
        this.sexName = sexName;
    }
}
  1. Product、ProductMapper、ProductService、ProductServiceImpl
    Product
@Data
@Accessors(chain = true)
@TableName("t_product")
public class Product {

    private Long id;
    private String name;
    private Integer price;
    @Version //标识乐观锁版本号字段
    private Integer version;
}

ProductMapper

@Repository
public interface ProductMapper extends BaseMapper<Product> {
}

ProductService

public interface ProductService extends IService {
}

ProductServiceImpl

public class ProductServiceImpl extends ServiceImpl implements ProductService {
}
  1. 测试代码
  • MybatisplusProductTest

@SpringBootTest
public class MybatisplusProductTest {

    @Autowired
    ProductMapper productMapper;

    @Test
    public void test01() {
        /**
         * ==>  Preparing: SELECT id,name FROM t_product
         * ==> Parameters:
         * <==    Columns: id, name
         * <==        Row: 1, 外星人笔记本
         * <==      Total: 1
         */
        QueryWrapper<Product> queryWrapper = new QueryWrapper();
        queryWrapper.select("id", "name");
        List<Product> listProduct = productMapper.selectList(queryWrapper);
        listProduct.forEach(System.out::println);
    }


    @Test
    public void test02() {
        //小李查询商品价格
        Product productLi = productMapper.selectById(1);
        System.out.println("小李查询的商品价格:" + productLi.getPrice());
        //小王查询商品价格
        Product productWang = productMapper.selectById(1);
        System.out.println("小王查询的商品价格:" + productWang.getPrice());
        /*//小李将商品价格+50
        productLi.setPrice(100);
        productMapper.updateById(productLi);*/
        //小李将商品价格+50
        productLi.setPrice(productLi.getPrice() + 50);
        productMapper.updateById(productLi);
        //小王将商品价格-30 (修改不成功)
        productWang.setPrice(productWang.getPrice() - 30);
        int result = productMapper.updateById(productWang);
        if (result == 0) {
            //@version只是控制其不进行更新,但是此时小王中获取的数据还是之前的100,因此要重新创建对象
            System.out.println("productWang.getPrice() = " + productWang.getPrice());//productWang.getPrice() = 70
            Product productNew = productMapper.selectById(1);
            productNew.setPrice(productNew.getPrice() - 30);
            productMapper.updateById(productNew);
        }
        //老板查询商品价格
        Product productBoss = productMapper.selectById(1);
        System.out.println("小李查询的商品价格:" + productBoss.getPrice());
    }
}
  • FastAutoGeneratorTest
    代码生成器
public class FastAutoGeneratorTest {
    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false&serverTimezone=GMT", "root", "root")
                .globalConfig(builder -> {
                    builder.author("baomidou") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir("D://mybatis_plus"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.baomidou") // 设置父包名
                            .moduleName("mybatisplus") // 设置父包模块名

                            //.pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); // 设置mapperXml生成路径
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus")); // 设置mapperXml生成路径
                })
                //设置逆向生成表
                .strategyConfig(builder -> {
                    builder.addInclude("t_user") // 设置需要生成的表名
                            .addTablePrefix("t_", "c_"); // 设置过滤表前缀
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();

    }
}
  • MybatisPlusEnumTest
@SpringBootTest
public class MybatisPlusEnumTest {

    @Autowired
    UserMapper userMapper;

    @Test
    public void test01() {
        /**
         * ==>  Preparing: INSERT INTO t_user ( uid, name, sex ) VALUES ( ?, ?, ? )
         * ==> Parameters: 1543962141062930433(Long), admin(String), 1(Integer)
         * <==    Updates: 1
         */
        User user = new User();
        user.setName("admin")
                .setSex(SexEnum.MALE);
        int result = userMapper.insert(user);
        System.out.println("result = " + result);
    }
}
  • MybatisPlusPageTest
@SpringBootTest
public class MybatisPlusPageTest {

    @Autowired
    UserMapper userMapper;

    @Test
    public void test1() {
        Page<User> page = new Page(1, 3);
        userMapper.selectPageVo(page, 20);
    }
}

  • MyBatisPlusPluginsTest
@SpringBootTest
public class MyBatisPlusPluginsTest {


    @Autowired
    private UserMapper userMapper;

    @Test
    public void test1() {
        /**
         * ==>  Preparing: SELECT uid AS id,name,age,email FROM t_user LIMIT ?
         * ==> Parameters: 3(Long)
         */
        Page<User> page= new Page<User>(1, 3);
        //返回page
        userMapper.selectPage(page, null);
        /**
         * [User(id=4, name=小明, age=21, email=test@qq.com), User(id=5, name=Gille, age=24, email=11155@qq.com)]
         * 1
         * 1
         * 2
         * false
         * false
         */
        System.out.println(page.getRecords());
        System.out.println(page.getCurrent());
        System.out.println(page.getPages());
        System.out.println(page.getTotal());
        System.out.println(page.hasNext());
        System.out.println(page.hasPrevious());


    }

}

  • MyBatisPlusServiceTest

@SpringBootTest
public class MyBatisPlusServiceTest {


    @Autowired
    private UserService userService;

    @Test
    public void testConunt() {
        //查询总记录数 select count(*) from user;
      int count = userService.count();
        System.out.println("总记录数: count = " + count);
    }


    /**
     * 批量添加在usermapper中没有
     * 因为usermapper是直接拼接成sql
     *
     */
    @Test
    public void insert() {
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setAge(10 + i)
                .setName("ybc" + i);
            list.add(user);
        }
        //循环insert into
       boolean bl = userService.saveBatch(list);
        System.out.println("bl = " + bl);
    }
}
  • MybatisPlusTest
@SpringBootTest
public class MybatisPlusTest {

    /**
     * userMapper为什么爆红?
     * 1、ioc只能存在类所对应的bean,不能存在接口所对应的bean
     * 2、ioc默认是将bean 进行装配的
     * 但是我们定义的是一个接口,导致可能无法装配,但是在
     * 运行的时候可以装配的
     * 3.可以在UserMapper中配置@Repository
     */
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectList() {
        //List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
        /**
         * Wrapper是条件构造器
         *
         * */
        //通过条件构造器来查询一个list集合,若没有集合,则可设置null
        List<User> list = userMapper.selectList(null);
        list.forEach(System.out::println);
    }

    /**
     * ==>  Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
     * ==> Parameters: 1542117549401255937(Long), 张三(String), 23(Integer), zhangsan@qq.com(String)
     * <==    Updates: 1
     */
    @Test
    public void testInsert() {
        User user = new User();
        user.setName("张三").setAge(23).setEmail("zhangsan@qq.com");
        int result = userMapper.insert(user);
        System.out.println("result======>" + result);
        //默认使用雪花算法来生成id
        // id   ======>1542117549401255937  bigint long
        System.out.println(" id   ======>" + user.getId());
    }

    /**
     * JDBC Connection [HikariProxyConnection@726483751 wrapping com.mysql.jdbc.JDBC4Connection@16da1abc] will not be managed by Spring
     * ==>  Preparing: DELETE FROM user WHERE id=?
     * ==> Parameters: 1542117549401255937(String)
     */
    @Test
    public void testDelete() {
        /**
         * 通过id删除用户信息
         * JDBC Connection [HikariProxyConnection@726483751 wrapping com.mysql.jdbc.JDBC4Connection@16da1abc] will not be managed by Spring
         * ==>  Preparing: DELETE FROM user WHERE id=?
         * ==> Parameters: 1542117549401255937(String)
         */
       /**
        *
        * int result =  userMapper.deleteById(1542118893906358273l);
        * System.out.println("result = " + result);
       */
        /**
         * ==>  Preparing: DELETE FROM user WHERE name = ? AND age = ?
         * ==> Parameters: 张三(String), 23(String)
         */
       /*Map<String, Object> map = new HashMap<>();
       map.put("name", "张三");
       map.put("age", "23");
       int result_map = userMapper.deleteByMap(map);
       System.out.println("result_map = " + result_map);*/
        /**
         * ==>  Preparing: DELETE FROM user WHERE id IN ( ? , ? , ? )
         * ==> Parameters: 1(Long), 2(Long), 3(Long)
         * <==    Updates: 3
          */
       List alist = Arrays.asList(1l, 2l , 3l);
       userMapper.deleteBatchIds(alist);
    }

    @Test
    public void testUpdate() {
        /**
         * ==>  Preparing: UPDATE user SET name=?, age=?, email=? WHERE id=?
         * ==> Parameters: aa1(String), 23(Integer), 1233@qq.com(String), 3(Long)
         * <==    Updates: 0
         */
        //修改用户信息
        User user = new User();
        user.setId(3l).setName("aa1").setAge(23).setEmail("1233@qq.com");
        userMapper.updateById(user);
    }

    @Test
    public void userSelect() {

      //通过id查询用户信息
        /**
         * ==>  Preparing: SELECT id,name,age,email FROM user WHERE id=?
         * ==> Parameters: 1(Long)
         * <==      Total: 0
         */
      User user_id = userMapper.selectById(1l);
        /**
         * ==>  Preparing: SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )
         * ==> Parameters: 1(Long), 2(Long), 3(Long)
         * <==      Total: 0
         */
      List<Long> longs = Arrays.asList(1l,2l,3l);
      //根据多个id执行
        //select * from user r where r.id in (?,?,?)
      List<User> listUser = userMapper.selectBatchIds(longs);
      listUser.forEach(System.out::println);
      //select * from user where name =? and age = ?
      Map<String,Object> map = new HashMap<>();
      map.put("name", "Jack");
      map.put("age", 20);
      List<User> usermap = userMapper.selectByMap(map);
      usermap.forEach(System.out::println);
      //System.out.println("usermap = " + usermap);

        //select * from user
      List<User> users = userMapper.selectList(null);
      users.forEach(System.out::println);
    }


    @Test
    public void testZidingyi() {
        /**
         * ==>  Preparing: select * from user r where r.id = ?
         * ==> Parameters: 2(Long)
         * <==      Total: 0
         */
        Map<String,Object> objectMap = userMapper.selectMapById(2l);
        System.out.println(objectMap);
    }

}
  • MyBatisPlusWrapperTest

@SpringBootTest
public class MyBatisPlusWrapperTest {

    @Autowired
    private UserMapper userMapper;

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

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

    @Test
    public void deleteWrapper() {
        /**
         * DELETE FROM t_user WHERE (email IS NULL)
         */
        //删除邮箱地址为null的用户信息
        //删除可以使用queryWrapper
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int result = userMapper.delete(queryWrapper);
        System.out.println("result = " + result);
    }

    @Test
    public void updateWrapperTest() {
        /**
         *  Preparing: UPDATE t_user SET name=?, email=? WHERE (age > ? AND name LIKE ? OR email IS NULL)
         * ==> Parameters: 小明(String), test@qq.com(String), 20(Integer), %a%(String)
         */
        //将年龄大于20并且用户名中包含有a或邮箱为null的用户信息修改
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("age", 20)
                .like("name", "a")
                .or()
                .isNull("email");
        User user = new User();
        user.setName("小明")
                .setEmail("test@qq.com");
        /**
         * 第一参数 设置填充内容  set
         * 第二参数 设置修改条件  where
         */
        int result = userMapper.update(user, queryWrapper);
        System.out.println("result = " + result);
    }

    @Test
    public void test05 () {
        /**
         * ==>  Preparing: UPDATE t_user SET name=?, email=? WHERE (name LIKE ? AND (age > ? OR email IS NULL))
         * ==> Parameters: 小红(String), test@qq.com(String), %a%(String), 20(Integer)
         * <==    Updates: 0
         */
        //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .like("name", "a")
                //lamda consumer接口 Consumer<Param> consumer
                //lambda中的条件有限执行
                .and(i-> {
                    i.gt("age", 20)
                            .or()
                            .isNull("email");
                });
        User user = new User();
        user.setName("小红")
                .setEmail("test@qq.com");
        int result = userMapper.update(user, queryWrapper);
        System.out.println("result = " + result);
    }

    @Test
    public void test6() {
        /**
         * ==>  Preparing: SELECT name,age,email FROM t_user
         */
        //查询用户的用户名、年龄、邮箱信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("name", "age", "email");
        List<Map<String, Object>> list = userMapper.selectMaps(queryWrapper);
        list.forEach(System.out::println);
    }

    @Test
    public void test7() {
        /**
         * ==>  Preparing: SELECT uid AS id,name,age,email FROM t_user
         * WHERE (uid IN (select uid from t_user where uid <= 100))
         */
        //查询id小于等于100的用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("uid","select " +
                " uid from t_user where uid <= 100");
        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);
    }

    @Test
    public void test8() {
        //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper
                .like("name", "a")
                //lamda consumer接口 Consumer<Param> consumer
                //lambda中的条件有限执行
                .and(i-> {
                    i.gt("age", 20)
                            .or()
                            .isNull("email");
                });
        updateWrapper.set("name", "晓红")
                .set("email","test@qq.com");
        int result = userMapper.update(null, updateWrapper);
        System.out.println("result = " + result);

    }

    @Test
    public void test9() {
        //import com.baomidou.mybatisplus.core.toolkit.StringUtils;
        String username = "";
        Integer ageBegin = 20;
        Integer ageEnd = 30;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //不为空字符串、不为null、不为空白符
        if (StringUtils.isNotBlank(username)) {
            queryWrapper.like("name", username);
        }
        if (ageBegin != null ) {
            queryWrapper.ge("age", ageBegin);
        }
        if (ageEnd != null) {
            queryWrapper.le("age", ageEnd);
        }
        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);
    }

    @Test
    public void test10() {
        /**
         * ==>  Preparing: SELECT uid AS id,name,age,email FROM t_user WHERE (age >= ? AND age <= ?)
         * ==> Parameters: 20(Integer), 30(Integer)
         */
        String username = "";
        Integer ageBegin = 20;
        Integer ageEnd = 30;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(username), "name", username)
                .ge(ageBegin != null, "age", ageBegin)
                .le(ageEnd != null , "age", ageEnd);
        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);
    }

    @Test
    public void test11() {
        String username = "";
        Integer ageBegin = 20;
        Integer ageEnd = 30;
        //防止字段名写错
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StringUtils.isNotBlank(username), User::getName, username)
                .ge(ageBegin != null, User::getAge, ageBegin)
                .le(ageEnd != null , User::getAge, ageEnd);
        List<User> userList = userMapper.selectList(lambdaQueryWrapper);
        userList.forEach(System.out::println);
    }

    @Test
    public void test12() {
        /**
         * ==>  Preparing: UPDATE t_user SET name=?,email=? WHERE (name LIKE ? AND (age > ? OR email IS NULL))
         * ==> Parameters: 晓红123(String), test123@qq.com(String), %a%(String), 20(Integer)
         */
        //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.like(User::getName, "a")
                .and(i->i.gt(User::getAge, 20).or()
                .isNull(User::getEmail));
        lambdaUpdateWrapper.set(User::getName, "晓红123")
                .set(User::getEmail, "test123@qq.com");
        int result = userMapper.update(null, lambdaUpdateWrapper);
        System.out.println("result = " + result);
    }
}

基本功能

通用mapper-----BaseMapper

通过BaseMapper来实现CRUD

@Test
    public void testSelectList() {
        //List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
        /**
         * Wrapper是条件构造器
         * */
        //通过条件构造器来查询一个list集合,若没有集合,则可设置null
        List<User> list = userMapper.selectList(null);
        list.forEach(System.out::println);
    }
    /**
     * ==>  Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
     * ==> Parameters: 1542117549401255937(Long), 张三(String), 23(Integer), zhangsan@qq.com(String)
     * <==    Updates: 1
     */
    @Test
    public void testInsert() {
        User user = new User();
        user.setName("张三").setAge(23).setEmail("zhangsan@qq.com");
        int result = userMapper.insert(user);
        System.out.println("result======>" + result);
        //默认使用雪花算法来生成id
        // id   ======>1542117549401255937  bigint long
        System.out.println(" id   ======>" + user.getId());
    }

    /**
     * JDBC Connection [HikariProxyConnection@726483751 wrapping com.mysql.jdbc.JDBC4Connection@16da1abc] will not be managed by Spring
     * ==>  Preparing: DELETE FROM user WHERE id=?
     * ==> Parameters: 1542117549401255937(String)
     */
    @Test
    public void testDelete() {
        /**
         * 通过id删除用户信息
         * JDBC Connection [HikariProxyConnection@726483751 wrapping com.mysql.jdbc.JDBC4Connection@16da1abc] will not be managed by Spring
         * ==>  Preparing: DELETE FROM user WHERE id=?
         * ==> Parameters: 1542117549401255937(String)
         */
       /**
        *
        * int result =  userMapper.deleteById(1542118893906358273l);
        * System.out.println("result = " + result);
       */
        /**
         * ==>  Preparing: DELETE FROM user WHERE name = ? AND age = ?
         * ==> Parameters: 张三(String), 23(String)
         */
       /*Map<String, Object> map = new HashMap<>();
       map.put("name", "张三");
       map.put("age", "23");
       int result_map = userMapper.deleteByMap(map);
       System.out.println("result_map = " + result_map);*/
        /**
         * ==>  Preparing: DELETE FROM user WHERE id IN ( ? , ? , ? )
         * ==> Parameters: 1(Long), 2(Long), 3(Long)
         * <==    Updates: 3
          */
       List alist = Arrays.asList(1l, 2l , 3l);
       userMapper.deleteBatchIds(alist);
    }

    @Test
    public void testUpdate() {
        /**
         * ==>  Preparing: UPDATE user SET name=?, age=?, email=? WHERE id=?
         * ==> Parameters: aa1(String), 23(Integer), 1233@qq.com(String), 3(Long)
         * <==    Updates: 0
         */
        //修改用户信息
        User user = new User();
        user.setId(3l).setName("aa1").setAge(23).setEmail("1233@qq.com");
        userMapper.updateById(user);
    }

    @Test
    public void userSelect() {

      //通过id查询用户信息
        /**
         * ==>  Preparing: SELECT id,name,age,email FROM user WHERE id=?
         * ==> Parameters: 1(Long)
         * <==      Total: 0
         */
      User user_id = userMapper.selectById(1l);
        /**
         * ==>  Preparing: SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )
         * ==> Parameters: 1(Long), 2(Long), 3(Long)
         * <==      Total: 0
         */
      List<Long> longs = Arrays.asList(1l,2l,3l);
      //根据多个id执行
        //select * from user r where r.id in (?,?,?)
      List<User> listUser = userMapper.selectBatchIds(longs);
      listUser.forEach(System.out::println);
      //select * from user where name =? and age = ?
      Map<String,Object> map = new HashMap<>();
      map.put("name", "Jack");
      map.put("age", 20);
      List<User> usermap = userMapper.selectByMap(map);
      usermap.forEach(System.out::println);
      //System.out.println("usermap = " + usermap);

        //select * from user
      List<User> users = userMapper.selectList(null);
      users.forEach(System.out::println);
    }
自定义功能

XXXmapper.xml文件中配置自定义的sql,一般为多表查询。

Service CRUD 接口
说明

1. 通用 Service CRUD 封装IService (opens new window)接口,进一步封装 CRUD 采用 get 查询单行 、remove 删除、 list 查询集合 、page 分页前缀命名方式区分 Mapper 层避免混淆
2. 泛型 T 为任意实体对象
3. 建议如果存在自定义通用 Service 方法的可能,请创建自己的IBaseService继承 Mybatis-Plus 提供的基类
对象, Wrapper 为 条件构造器

//实体了
    boolean saveBatch(Collection<T> entityList, int batchSize);
    @Transactional(
        rollbackFor = {Exception.class}
    )
    //如果有id 修改,没有id则添加
    default boolean saveOrUpdateBatch(Collection<T> entityList) {
        return this.saveOrUpdateBatch(entityList, 1000);
    }

IService

MyBatis-Plus中有一个接口IService和其实现类ServiceImpl,封装了常见的业务层逻辑

创建Service接口和实现类

代补:
UserService

import com.baomidou.mybatisplus.extension.service.IService;
import com.cjw.mybaitsplusdatasource.pojo.User;
public interface UserService extends IService<User> {
}

UserServiceImpl

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cjw.mybaitsplusdatasource.mapper.UserMapper;
import com.cjw.mybaitsplusdatasource.pojo.User;
import com.cjw.mybaitsplusdatasource.service.UserService;
import org.springframework.stereotype.Service;
@Service
//@DS(value = "slave_1")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

UserMapper

@Repository
public interface UserMapper extends BaseMapper<User> {
}

Mybatis-Plus的常用注解

@Table_name
  1. 作用:当实体类和表名不一致的时候,设置实体类所对应的表名
@TableName("t_user")
public class User {
  1. 全局设置表的统一前缀
# 配置mybatis_plus打印日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    #默认位置
  mapper-locations: classpath*:/mapper/**/*.xml
  #设置全局表的前缀  在userMapper.xml中是失败的没有找到t_user表
  global-config:
    db-config:
      table-prefix: t_
@TableId
  1. 作用:mybatisplus默认会将id作为主键,表名的ID和实体类不对应时,可以使用@TableId,将属性所对应的字段指定为主键。
     @TableId
    private Long uid; //数据库bigint
   或者这种
    @TableId("uid")
    private Long id;
  1. TableId中的value属性
    用于指定主键的字段,当实体类是id时,而字段名不是id时。
    //value的作用:将属性指定字段名
    @TableId("uid")
    private Long id;
  1. TableId中的type属性
  • 自定递增:满足两个条件一个是数据库中的主键必须时自增的,另一个条件时Type指定自增
  • type作用设置主键的生成策略
    @TableId(value = "uid", type = IdType.AUTO)
    private Long id;
  1. 全局配置主键生成策略
    在这里插入图片描述

当我们设置了id的值,那么就不会使用雪花算法。

雪花算法
  1. 背景
    需要选择合适的方案去应对数据规模的增长,以应对逐渐增长的访问压力和数据量。
    数据库的扩展方式主要包括:业务分表、主从复制、数据库分表

  2. 数据库分表
    将不同业务数据分散存储到不同的数据库服务器,能够支撑百万甚至千万用户规模的业务,但如果业务继续发展,同一业务的单表数量也会达到带台数据库服务器的处理瓶颈,例如,淘宝的几亿用户数据。如果全部存放在一台数据库服务器的一张表中,肯定是无法满足性能要求的,此时就要对单表数据进行拆分。
    单表数据拆分有两种方式:垂直分表和水平分表,示意图如下:
    在这里插入图片描述

  3. 垂直分表
    垂直分表适合将表中某些不常用且占用了大量空间的列拆分出去。
    例如:前面示意图中的nickname和description字段,假设我们是一个婚恋网站,用户在筛选其他用户的时候,主要是用age和sex两个字段进行查询,而nickname和descriptioin两个字段主要用于展示,一般不会在业务查询中用到。description本身又比较长,因此我们可以将这两个字段独立到另外一张表中,这样在查询age和sex时,就能带来一定的性能提升。

  4. 水平分表
    水平分表适合表行数特别大的表,有的公司要求单表行数超过5000万就必须进行分表,这个数字可以作为参考,但并不是绝对标准,关键还是要看表的访问特性。对于一些比较复杂的表。可能超过1000万就要分表了;而对于一些简单的表,即使存储数据超过1亿行,也可以不分表。
    但不管怎么样,当看到表的数据量达到千万级别时,作为架构就要警觉起来,因为这很可能是架构的性能瓶颈或者隐患。
    水平分表相比垂直分表,会引入更多的复杂性,例如要求全局唯一的数据id该如何处理

  5. 主键自增

  • 以最常见的用户ID为例,可以按照1000000的范围大小进行分段,1`9999999放到表1中,10000000~19999999放到表2中,以此类推。
  • 复杂点:分段大小的选取,分段大小会导致切分后字表数量过多,增加维护量复杂度;分段太大可能会导致单表依然存在性能问题,一般建议分段大小在100万至2000万之间,具体需要根据业务选取合适的分段大小。
  • 优点:可以随着数据的增加平滑地扩充新的表,例如:现在的用户是100万,如果增加到1000万,只需要增加新的表就可以了,原有的数据不需要动。
  • 缺点:分布不均匀,例如按照1000万来进行分表,有可能某个分段实际存储的数据量只有1条,而另外一个分段实际存储的数据量有1000万条。
  1. 取模
  • 同样以用户ID为例,例如我们一开始就规划了10个数据库表,可以简单地用user_id % 10的值来表示数据所属的数据库表编号,ID为985的用户放到编号为5的子表中,ID为10086的用户放到编号为6的子表中。
  • 复杂点: 初始表数量的确定。表数量太多维护比较麻烦,表数量太少又可能导致单表性能存在的问题
  • 优点:表分布比较均匀
  • 缺点:扩充新的表很麻烦,所有数据都要重分布
  1. 雪花算法
    雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键不重复性,以及相同表的主键的有序性。
  • 核心思想:
    长度工64bit(一个long型)
    首先是一个符号位,1bit标识,由于long基本类型在java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。
    4bit时间戳(毫秒级),存储的是时间戳的差值(当前时间戳 + 开始时间戳),结果约等于69.73年
    10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)
    12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID)。
    在这里插入图片描述
  • 优点: 整体上按照时间自增顺序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。
@TableField

1. 将下划线转换为驼峰格式(默认数据库表中user_name,字段为userName)
2. 当字段名称和数据库字段名称不一致时,则使用@TableField

@TableLogic
  1. 逻辑删除
  • 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
  • 逻辑删除:做删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看此条数据记录
  • 使用场景:可以进行数据恢复
  1. 实现逻辑删除
  • step1: 数据库中创建逻辑删除状态列,设置默认值为0
    在这里插入图片描述
    当执行查询的时候,就是is_deleted=0,而不会将is_deleted所有结果都查询出来。
    在这里插入图片描述
    在这里插入图片描述

条件构造器简介

wrapper介绍
  • wrapper: 条件构造抽象类,最顶端父类
    • AbstractWrapper:用于查询条件封装,生成sql的where条件
      • QueryWrapper: 查询条件封装
      • UpdateWrapper: Update条件封装
      • AbstractLambdaWrapper: 使用Lambda语法
        • LambdaQueryWrapper: 用于Lambda语法使用的查询Wrapper
        • LambdaUpdateWrapper: Lambda更新封装Wrapper
          在这里插入图片描述
QueryWrapper

查询、修改、删除都可以使用

组装查询条件
    @Test
    public void selectListMapper() {
        /**
         * ==>  Preparing: SELECT uid AS id,name,age,email FROM t_user WHERE (name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
         * ==> Parameters: %张三%(String), 20(Integer), 30(Integer)
         */
        //查询用户名包含a,年龄在20到30之间,邮箱信息不为null的用户信息。
        QueryWrapper<User> queryWrapper = new QueryWrapper();
        queryWrapper.like("name", "张三")
                .between("age", 20, 30)
                .isNotNull("email");
        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);
    }
组装排序条件——orderbyasc 和 orderbydesc
    @Test
    public void test02()  {
        /**
         * SELECT uid AS id,name,age,email FROM t_user ORDER BY age DESC,uid ASC
         */
        //查询用户信息,按照年龄降序排序,若年龄相同,按照id升序排序
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("age")
                .orderByAsc("uid");
        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);
    }
组装删除条件
    @Test
    public void deleteWrapper() {
        /**
         * DELETE FROM t_user WHERE (email IS NULL)
         */
        //删除邮箱地址为null的用户信息
        //删除可以使用queryWrapper
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int result = userMapper.delete(queryWrapper);
        System.out.println("result = " + result);
    }
实现修改功能
  @Test
    public void updateWrapperTest() {
        /**
         *  Preparing: UPDATE t_user SET name=?, email=? WHERE (age > ? AND name LIKE ? OR email IS NULL)
         * ==> Parameters: 小明(String), test@qq.com(String), 20(Integer), %a%(String)
         */
        //将年龄大于20并且用户名中包含有a或邮箱为null的用户信息修改
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("age", 20)
                .like("name", "a")
                .or()
                .isNull("email");
        User user = new User();
        user.setName("小明")
                .setEmail("test@qq.com");
        /**
         * 第一参数 设置填充内容  set
         * 第二参数 设置修改条件  where
         */
        int result = userMapper.update(user, queryWrapper);
        System.out.println("result = " + result);
    }
条件的优先级
@Test
    public void test05 () {
        /**
         * ==>  Preparing: UPDATE t_user SET name=?, email=? WHERE (name LIKE ? AND (age > ? OR email IS NULL))
         * ==> Parameters: 小红(String), test@qq.com(String), %a%(String), 20(Integer)
         * <==    Updates: 0
         */
        //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .like("name", "a")
                //lamda consumer接口 Consumer<Param> consumer
                //lambda中的条件优先执行
                .and(i-> {
                    i.gt("age", 20)
                            .or()
                            .isNull("email");
                });
        User user = new User();
        user.setName("小红")
                .setEmail("test@qq.com");
        int result = userMapper.update(user, queryWrapper);
        System.out.println("result = " + result);
    }
组装select字句
    @Test
    public void test6() {
        /**`在这里插入代码片`
         * ==>  Preparing: SELECT name,age,email FROM t_user
         */
        //查询用户的用户名、年龄、邮箱信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("name", "age", "email");
        List<Map<String, Object>> list = userMapper.selectMaps(queryWrapper);
        list.forEach(System.out::println);
    }
组装子查询
@Test
    public void test7() {
        /**
         * ==>  Preparing: SELECT uid AS id,name,age,email FROM t_user
         * WHERE (uid IN (select uid from t_user where uid <= 100))
         */
        //查询id小于等于100的用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("uid","select " +
                " uid from t_user where uid <= 100");
        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);
    }
通过UpdateWrapper实现修改功能

使用UpdateWrapper不用使用实体类它本身有set方法,而QueryWrapper则需要使用实体类修改值

    @Test
    public void test8() {
        //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper
                .like("name", "a")
                //lamda consumer接口 Consumer<Param> consumer
                //lambda中的条件有限执行
                .and(i-> {
                    i.gt("age", 20)
                            .or()
                            .isNull("email");
                });
        updateWrapper.set("name", "晓红")
                .set("email","test@qq.com");
        int result = userMapper.update(null, updateWrapper);
        System.out.println("result = " + result);

    }
模拟开发中组装条件的情况
@Test
    public void test9() {
        //import com.baomidou.mybatisplus.core.toolkit.StringUtils;
        String username = "";
        Integer ageBegin = 20;
        Integer ageEnd = 30;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //不为空字符串、不为null、不为空白符
        if (StringUtils.isNotBlank(username)) {
            queryWrapper.like("name", username);
        }
        if (ageBegin != null ) {
            queryWrapper.ge("age", ageBegin);
        }
        if (ageEnd != null) {
            queryWrapper.le("age", ageEnd);
        }
        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);
    }
使用condition组装条件
    @Test
    public void test10() {
        /**
         * ==>  Preparing: SELECT uid AS id,name,age,email FROM t_user WHERE (age >= ? AND age <= ?)
         * ==> Parameters: 20(Integer), 30(Integer)
         */
        String username = "";
        Integer ageBegin = 20;
        Integer ageEnd = 30;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(username), "name", username)
                .ge(ageBegin != null, "age", ageBegin)
                .le(ageEnd != null , "age", ageEnd);
        List<User> userList = userMapper.selectList(queryWrapper);
        userList.forEach(System.out::println);
    }
LambdaQueryWrapper
    @Test
    public void test11() {
        String username = "";
        Integer ageBegin = 20;
        Integer ageEnd = 30;
        //防止字段名写错
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StringUtils.isNotBlank(username), User::getName, username)
                .ge(ageBegin != null, User::getAge, ageBegin)
                .le(ageEnd != null , User::getAge, ageEnd);
        List<User> userList = userMapper.selectList(lambdaQueryWrapper);
        userList.forEach(System.out::println);
    }
LambdaUpdateWrapper
    @Test
    public void test12() {
        /**
         * ==>  Preparing: UPDATE t_user SET name=?,email=? WHERE (name LIKE ? AND (age > ? OR email IS NULL))
         * ==> Parameters: 晓红123(String), test123@qq.com(String), %a%(String), 20(Integer)
         */
        //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.like(User::getName, "a")
                .and(i->i.gt(User::getAge, 20).or()
                .isNull(User::getEmail));
        lambdaUpdateWrapper.set(User::getName, "晓红123")
                .set(User::getEmail, "test123@qq.com");
        int result = userMapper.update(null, lambdaUpdateWrapper);
        System.out.println("result = " + result);
    }

MyBatis-Plus分页插件的配置和使用

分页插件

MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能。

  1. 添加配置类
    配置类中添加分页插件,在配置类中可以将配置在application.yml中的包扫描配置在配置类中
@Configuration
/**
 * 在springboot 使用mybatis需要
 * 设置mapper接口和映射文件所在的包
 */
@MapperScan("com.cjw.mybatisplus.mybatisplusdemo.mapper")
public class Mybatisplusconfig {
    @Bean
    public MybatisPlusInterceptor  mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
  1. 处理分页设置
    @Test
    public void test1() {
        /**
         * ==>  Preparing: SELECT uid AS id,name,age,email FROM t_user LIMIT ?
         * ==> Parameters: 3(Long)
         */
        Page<User> page= new Page<User>(1, 3);
        //返回page
        userMapper.selectPage(page, null);
        System.out.println(page);
    }
  1. 处理分页相关数据获取
   @Test
    public void test1() {
        /**
         * ==>  Preparing: SELECT uid AS id,name,age,email FROM t_user LIMIT ?
         * ==> Parameters: 3(Long)
         */
        Page<User> page= new Page<User>(1, 3);
        //返回page
        userMapper.selectPage(page, null);
        /**
         * [User(id=4, name=小明, age=21, email=test@qq.com), User(id=5, name=Gille, age=24, email=11155@qq.com)]
         * 1
         * 1
         * 2
         * false
         * false
         */
        System.out.println(page.getRecords());
        System.out.println(page.getCurrent());
        System.out.println(page.getPages());
        System.out.println(page.getTotal());
        System.out.println(page.hasNext());
        System.out.println(page.hasPrevious());
    }
自定义分页功能
  1. 自定义实体类别名
# 配置mybatis_plus打印日志
mybatis-plus:
 #global-config:
 #   db-config:
 #     table-prefix: t_   #设置全局表的前缀
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:/mapper/**/*.xml     #默认位置
  #配置类型别名
  type-aliases-package: com.cjw.mybatisplus.mybatisplusdemo.pojo
  1. UserMapper
    分页插件作用于我们自定义的分页时,第一个参数必须是Page
 //分页插件作用于我们自定义的分页时,第一个参数必须是Page
    //@param相当于mapper.xml中的parameterType传递参数
    /**
     * 通过年龄查询用户信息并分页
     * @param page mybatis-plus提供的分页参数,必须第一个位置
     * @param age 
     * @return
     */
  //  Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);
      Page<User> selectPageVo( Page<User> page,  Integer age);
  1. userMapper.xml
<!--
    Page<User> selectPageVo(@Param("age") Page<User> page, @Param("age") Integer age);
-->
    <select id="selectPageVo" parameterType="User" resultType="User">
        select uid,name,age,email from t_user
         where age > #{age}
    </select>
  1. 测试自定义分页
==>  Preparing: SELECT COUNT(*) FROM t_user WHERE age > ?
==> Parameters: 20(Integer)
<==    Columns: COUNT(*)
<==        Row: 2
<==      Total: 1
@SpringBootTest
public class MybatisPlusPageTest {
    @Autowired
    UserMapper userMapper;
    @Test
    public void test1() {
        Page<User> page = new Page(1, 3);
        userMapper.selectPageVo(page, 20);
    }
}
乐观锁插件

乐观锁插件 通过每次更新时查询版本号,来进行更新

场景

一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去吧商品价格增加50元。小李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150员,价格太高。可能会影响销量。又通知小王,你把商品价格降低30元。
此时,小李和小王同时操作商品后台系统,小李操作的时候,系统先取出商品价格100元;小王也在操作,取出的商品价格也是100元。小李将价格增加了50元,并将100+50=150元存入了数据库;小王将商品减了30元,并将100-30=70元存储了数据库。是的,如果没有锁,小李的操作就完全被小王的覆盖了。
现在商品价格是70元,比成本价低10元,几分钟后,这个商品很快出售了1千多件商品,老板亏了1万多。

乐观锁和悲观锁

上面的故事,如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了,如果被修改过了,则重新取出的被修改后的价格,150元。这样他会将120元存入数据库。
如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格等操作,也会保证最终的价格是120元。

模拟修改冲突
//创建表结构
create table t_product (
	id bigint(20) not null comment '主键ID',
	name varchar(30) null default null comment '商品名称',
	price int(11) default 0 COMMENT '价格',
	version int(11) default 0 comment '乐观锁版本号',
	PRIMARY key (id)
)
//插入数据
insert into t_product(id, name, price)
value(1, '外星人笔记本', 100);
commit;
乐观锁实现流程

数据库中添加version字段
取出记录时,获取当前version

select id, name, price,version from product where id = 1

更新时,version + 1,如果where语句中的version版本不对,则更新失败

update product set price=price + 50, version = version + 1 where id = 1 and version = 1;
Mybatis-plus实现乐观锁

实体类中添加注解,修改实现类

@Data
@Accessors(chain = true)
@TableName("t_product")
public class Product {

    private Long id;
    private String name;
    private Integer price;
    @Version //标识乐观锁版本号字段
    private Integer version;
}

配置文件中添加乐观锁插件

 Parameter 'MP_OPTLOCK_VERSION_ORIGINAL' not found. Available parameters are [param1, et]

mybatisplus将插件写法更新如下:注释的是旧写法

@Configuration
/**
 * 在springboot 使用mybatis需要
 * 设置mapper接口和映射文件所在的包
 */
@MapperScan("com.cjw.mybatisplus.mybatisplusdemo.mapper")
public class Mybatisplusconfig {
   @Bean
    public MybatisPlusInterceptor  mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
    //等价于
   /* *//**
     * 添加分页插件
     * @return
     *//*
    @Bean
    public PaginationInnerInterceptor paginationInnerInterceptor() {
        return new PaginationInnerInterceptor();
    }
    *//**
     * 添加乐观锁插件
     * @return
     *//*
    @Bean
    public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
        return new OptimisticLockerInnerInterceptor();
    }*/
}

测试乐观锁代码

 @Test
    public void test02() {
        //小李查询商品价格
        Product productLi = productMapper.selectById(1);
        System.out.println("小李查询的商品价格:" + productLi.getPrice());
        //小王查询商品价格
        Product productWang = productMapper.selectById(1);
        System.out.println("小王查询的商品价格:" + productWang.getPrice());
/*        //小李将商品价格+50
        productLi.setPrice(100);
        productMapper.updateById(productLi);*/
        //小李将商品价格+50
        productLi.setPrice(productLi.getPrice() + 50);
        productMapper.updateById(productLi);
        //小王将商品价格-30 (修改不成功)
        productWang.setPrice(productWang.getPrice() - 30);
        productMapper.updateById(productWang);
        //老板查询商品价格
        Product productBoss = productMapper.selectById(1);
        System.out.println("小李查询的商品价格:" + productBoss.getPrice());
        /**
         * ==>  Preparing: SELECT id,name,price,version FROM t_product WHERE id=?
         * ==> Parameters: 1(Integer)
         * <==    Columns: id, name, price, version
         * <==        Row: 1, 外星人笔记本, 150, 5
         * <==      Total: 1
         */
    }
优化修改流程
   @Test
    public void test02() {
        //小李查询商品价格
        Product productLi = productMapper.selectById(1);
        System.out.println("小李查询的商品价格:" + productLi.getPrice());
        //小王查询商品价格
        Product productWang = productMapper.selectById(1);
        System.out.println("小王查询的商品价格:" + productWang.getPrice());
        /*//小李将商品价格+50
        productLi.setPrice(100);
        productMapper.updateById(productLi);*/
        //小李将商品价格+50
        productLi.setPrice(productLi.getPrice() + 50);
        productMapper.updateById(productLi);
        //小王将商品价格-30 (修改不成功)
        productWang.setPrice(productWang.getPrice() - 30);
        int result = productMapper.updateById(productWang);
        if (result == 0) {
            //@version只是控制其不进行更新,但是此时小王中获取的数据还是之前的100,因此要重新创建对象
            System.out.println("productWang.getPrice() = " + productWang.getPrice());//productWang.getPrice() = 70
            Product productNew = productMapper.selectById(1);
            productNew.setPrice(productNew.getPrice() - 30);
            productMapper.updateById(productNew);
        }
        //老板查询商品价格
        Product productBoss = productMapper.selectById(1);
        System.out.println("小李查询的商品价格:" + productBoss.getPrice());
    }

通用枚举

表中的有些字段值是固定的,例如性别(男或女),此时我们可以使用MyBatis-Plus通用枚举来实现
数据库中t_user中sex字段
在这里插入图片描述
定义枚举类

@Getter
public enum SexEnum {
     MALE(1, "男"),
     FEMALE(2, "女");
     @EnumValue //将注解所标识的属性的值注入到数据库中
    private Integer sex;
    private String sexName;
    SexEnum(Integer sex, String sexName) {
        this.sex = sex;
        this.sexName = sexName;
    }
}

扫描枚举包

# 配置mybatis_plus打印日志
mybatis-plus:
 #global-config:
 #   db-config:
 #     table-prefix: t_   #设置全局表的前缀
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:/mapper/**/*.xml     #默认位置
  #配置类型别名,不区分大小写
  type-aliases-package: com.cjw.mybatisplus.mybatisplusdemo.pojo
  #扫描通用枚举的包
  type-enums-package: com.cjw.mybatisplus.mybatisplusdemo.enums

处理数据添加测试

    @Test
    public void test01() {
        /**
         * ==>  Preparing: INSERT INTO t_user ( uid, name, sex ) VALUES ( ?, ?, ? )
         * ==> Parameters: 1543962141062930433(Long), admin(String), 1(Integer)
         * <==    Updates: 1
         */
        User user = new User();
        user.setName("admin")
                .setSex(SexEnum.MALE);
        int result = userMapper.insert(user);
        System.out.println("result = " + result);
    }

代码生成器

  1. 引入依赖
    <dependency>
           <groupId>com.baomidou</groupId>
           <artifactId>mybatis-plus-generator</artifactId>
           <version>3.5.1</version>
       </dependency>

       <dependency>
           <groupId>org.freemarker</groupId>
           <artifactId>freemarker</artifactId>
       </dependency>
  1. 快速生成
public class FastAutoGeneratorTest {
    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false&serverTimezone=GMT", "root", "root")
                .globalConfig(builder -> {
                    builder.author("baomidou") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir("D://mybatis_plus"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.baomidou") // 设置父包名
                            .moduleName("mybatisplus") // 设置父包模块名
                            //.pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); // 设置mapperXml生成路径
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus")); // 设置mapperXml生成路径
                })
                //设置逆向生成表
                .strategyConfig(builder -> {
                    builder.addInclude("t_user") // 设置需要生成的表名
                            .addTablePrefix("t_", "c_"); // 设置过滤表前缀
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();
    }
}
  1. 代码生成器生成如下:
    在这里插入图片描述

多数据源

场景说明:
我们创建两个库,分别为mybatis_plus(原库)与mybaits_plus1(新建),将mybaits_plus库的product表移动到mybatis_plus_1库,这样每个库一张表,通过一个测试用例分别获取用户数据与商品数据,如果获取到说明多库模拟成功。

  1. 创建数据库及表
create database mybatis_plus_1;
create table t_product
(
	id bigint(20) not null comment '主键ID',
	name varchar(30) null default null comment '商品名称',
	price int default 0 comment '价格',
	version int default 0 comment '乐观锁版本号',
	primary key (id)
);
insert into t_product (id, name, price)
values(1, '外星人笔记本', 100);
commit;
alter table t_product add COLUMN sex int(2) comment '性别';
select * from t_product;
  1. 引入依赖
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>
  1. 配置数据源
    说明:注释掉之前的数据库连接,添加新配置
#数据源 spring boot中默认所使用的数据源
spring:
  datasource:
    dynamic:
    #设置默认的数据源或者数据源组,默认值即为master
     primary: master
    #严格匹配数据源,默认falsetrue未匹配到指定数据源时异常,false使用默认数据源
     strict: false
     datasource:
       master:
         url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false&serverTimezone=GMT
         driver-class-name: com.mysql.jdbc.Driver
         username: root
         password: root
       slave_1:
         url: jdbc:mysql://localhost:3306/mybatis_plus_1?characterEncoding=utf-8&userSSL=false&serverTimezone=GMT
         driver-class-name: com.mysql.jdbc.Driver
         username: root
         password: root
  1. 创建用户Service
    在这里插入图片描述

  2. 测试

@SpringBootTest
public class mybatisplusTest {
    @Autowired
    UserMapper userMapper;
    @Autowired
    UserService userService;
    @Test
    public void test01() {
       User user =  userMapper.selectById(1);
        System.out.println("user = " + user);
    }
    @Test
    public void test02() {
        /**
         * ==>  Preparing: SELECT uid AS id,name,age,email,sex FROM t_user WHERE uid=?
         * ==> Parameters: 1(Integer)
         * <==      Total: 0
         */
        User user = userService.getById(1);
        System.out.println("user = " + user);
    }
}

结果:
1、 都能顺利获取对象,则测试成功
2、如果我们实现读写分离,将写操作方法加上主库数据源,读操作方法加上从库数据源,自动切换,是不是就能实现读写分离

MyBatisX插件

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
TUser变成了User
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
insertSelective//当传入

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值