MybatisPlus

MybataisPlus可以节省大量工作时间,所有的CRUD代码都可以自动化完成

JPA、tk-mapper、MyBatisPlus

简介

是什么? MYBatis是简化JDBC操作

官网:简介 | MyBatis-Plus (baomidou.com)

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

特性:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求,以后简单的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 操作智能分析阻断,也可自定义拦截规则,预防误操作

快速入门

使用第三方组件:

1、导入对应的依赖

2、研究依赖如何配置

3、代码如何编写

4、提高扩展技术能力

步骤:

1、创建数据库 mybatis_plus

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)
);
-- 真实开发中,version(乐观锁)、deleted(逻辑删除)、gmt_create、gmt_mdified

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');

3、编写项目,初始化项目 springboot项目

4、导入依赖

 <dependencies>


        <!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--mybatis-plus 依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>



        <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>
    </dependencies>

使用mybatis-plus 可以节省大量的代码。尽量不要同时导入mybatis和mybatis-plus!版本差异

5、连接数据库,这一步和mybatis相同

# mysql5
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?userSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#mysql8 需要添加时区

6、

传统方式:pojo-dao(连接mybatis,配置mapper.xml文件)-service-controller

使用mybatis-plus之后:

  • pojo
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
  • mapper接口
// 在对应的Mapper上面继承基本类的BaseMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.p.mybatis_plus.pojo.User;
import org.springframework.stereotype.Repository;

@Repository// 代表持久层
// 对哪个类操作就 添加哪个属性  如需要对User进行操作,BaseMapper<>  就添加User 泛型
public interface UserMapper extends BaseMapper<User> {
    //所有的CRUD操作已经完成了
    /*
    * 不需要像以前的配置一大堆文件了
    * */
}
  • 主启动类
@SpringBootApplication
//扫描 mapper文件
@MapperScan("com.p.mybatis_plus.mapper")
public class MybatisPlusApplication {

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

}
  • 测试使用
@SpringBootTest
class MybatisPlusApplicationTests {

    //继承了BaseMapper,所有的方法都来自自己的父类,
    // 也可以编写自己的扩展方法
    @Autowired
    private UserMapper userMapper;


    @Test
    void contextLoads() {
        //参数是一个Wrapper,条件构造器,这里先不用 null
        //查询全部用户
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::print);
    }

}
  • 结果
User(id=1, name=Jone, age=18, email=test1@baomidou.com)User(id=2, name=Jack, age=20, email=test2@baomidou.com)User(id=3, name=Tom, age=28, email=test3@baomidou.com)User(id=4, name=Sandy, age=21, email=test4@baomidou.com)User(id=5, name=Billie, age=24, email=test5@baomidou.com)

配置日志输出

目前所有的sql是不可见的,希望知道他是怎么执行的,所以必须查看日志

# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
```xml
JDBC Connection [HikariProxyConnection@1832101486 wrapping com.mysql.cj.jdbc.ConnectionImpl@2f14b0f6] will not be managed by Spring
==>  Preparing: SELECT id,name,age,email FROM user 
==> Parameters: 
<==    Columns: id, name, age, email
<==        Row: 1, Jone, 18, test1@baomidou.com
<==        Row: 2, Jack, 20, test2@baomidou.com
<==        Row: 3, Tom, 28, test3@baomidou.com
<==        Row: 4, Sandy, 21, test4@baomidou.com
<==        Row: 5, Billie, 24, test5@baomidou.com
<==      Total: 5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4a2e7bcb]
User(id=1, name=Jone, age=18, email=test1@baomidou.com)User(id=2, name=Jack, age=20, email=test2@baomidou.com)User(id=3, name=Tom, age=28, email=test3@baomidou.com)User(id=4, name=Sandy, age=21, email=test4@baomidou.com)User(id=5, name=Billie, age=24, email=test5@baomidou.com)

CRUD扩展

insert

 //测试插入
    @Test
    public void testInsert(){
        User user = new User();
        user.setName("P");
        user.setAge(12);
        user.setEmail("123");

        int insert = userMapper.insert(user);  //在没有设置id值时,会自动生动ID
        System.out.println(insert); //受影响的行数
        System.out.println(user); //发现ID 会自动回填
    }

结果

      Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? ) 
==> Parameters: 1578286574218575874(Long), P(String), 12(Integer), 123(String)  # sql语句
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1756f7cc]
1   # 收影响的行数
User(id=1578286574218575874, name=P, age=12, email=123)  # id 自动回填

数据库插入的id默认值为:全局的唯一ID

主键生成策略

默认ID_WORKER 全局唯一id

 //id 对应数据库中的主键 (uuid、自增id、雪花算法、redis、zookeeper)
    @TableId(type = IdType.ID_WORKER)
    private Long id;
    private String name;
    private Integer age;
    private String email;

分布式统唯一id生成算法:雪花算法

雪花算法:

snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,如:北京、上海,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。

可以保证几乎全球唯一

分布式高并发的环境下,最常见的就是每年双十一的十二点,大量用户同时抢购同一商品,毫秒级的时间下可能生成数万个订单,此时确保生成订单ID的唯一性变得至关重要。此外,在秒杀环境下,不仅要保障ID唯一性、还得确保ID生成的优先度,先抢购到的要优先创建。

雪花算法(snowflake)最早是twitter内部使用分布式环境下的唯一ID生成算法。
雪花算法使用64位long类型的数据存储id
0 - 0000000000 0000000000 0000000000 0000000000 0 - 0000000000 - 000000000000
符号位              时间戳                             机器码           序列号

主键自增 IdType.AUTO

需要配置主键自增

1、实体类字段上@TableId(type = IdType.AUTO)

2、数据库字段一定是自增

其余的源码解释

public enum IdType {
    AUTO(0),  //数据库id自增
    NONE(1), //未设置主键
    INPUT(2), //手动输入  就需要自己配置id了,默认为null
    ID_WORKER(3), //默认的全局唯一id
    UUID(4), //全局唯一id uuid
    ID_WORKER_STR(5); //ID_WORKER 字符串表示法

更新操作

  //测试更新
    @Test
    public void testUpdate(){
        User user = new User();
        //通过条件自动拼接动态SQL
        user.setId(6L);
        user.setName("更新后的操作");
        // updateById 参数是一个对象
        int i = userMapper.updateById(user);
        System.out.println(i);
    }

所有的sql都是自动帮你动态配置的!

自动填充

如:创建时间,修改时间!这些操作一般都是自动化完成的,不希望手动更新

阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified 几乎所有的表都要配置上!需要自动化

方式一:数据库级别(工作中不建议修改数据库)

1、在表中新增字段create_time,update_time

2、实体类中

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    //id 对应数据库中的主键 (uuid、自增id、雪花算法、redis、zookeeper)
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private Date createTime;//数据库中的字段是 create_time  因可以自动识别驼峰
    private Date updateTime;
}

3、测试

方式二:代码级别

1、删除数据库中的默认值、跟新操作

ADD COLUMN `create_time`  datetime NULL COMMENT '新增时间' AFTER `email`;
ADD COLUMN `update_time`  datetime NULL COMMENT '更改时间' AFTER `create_time`;

2、实体类字段属性上需要增加注解

public enum FieldFill {
    DEFAULT,
    INSERT,   // 插入
    UPDATE,   //更新
    INSERT_UPDATE; //插入时更新
}


// 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    //id 对应数据库中的主键 (uuid、自增id、雪花算法、redis、zookeeper)
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;

    @TableField(fill = FieldFill.INSERT )
    private Date createTime;//数据库中的字段是 create_time  因可以自动识别驼峰
    @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......");
        //MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
            //                                想要修改的字段名   要插入的字段数据    要给哪个数据处理
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

    //更新时额填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

4、测试

插入时
==>  Preparing: INSERT INTO user ( name, age, email, create_time, update_time ) VALUES ( ?, ?, ?, ?, ? ) 
==> Parameters: P(String), 120(Integer), 123(String), 2022-10-09 15:10:04.837(Timestamp), 2022-10-09 15:10:04.837(Timestamp)
<==    Updates: 1

User(id=1578286574218575875, name=P, age=120, email=123, createTime=Sun Oct 09 15:10:04 CST 2022, updateTime=Sun Oct 09 15:10:04 CST 2022)

乐观锁

乐观锁:十分乐观,认为不会出现问题,无论干什么不去上锁,如果出现了问题,再次更新值测试

悲观锁:十分悲观,认为总是会出现问题,无论干什么都会上锁!再去操作

乐观锁实现方式:

  • 取出记录值,获取当前version
  • 更新时,带上这个version
  • 执行更新时,set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
乐观锁:1、先查询,获取版本号 version =1
====A 线程
update user set name= "P",version= version+1
where id = 2 and version =1


==B 线程 抢先完成,这个适合 version= 2,会导致A修改失败
update user set name= "P",version= version+1
where id = 2 and version =1

1、给数据中增加version字段

ALTER TABLE `user`
ADD COLUMN `version`  int(255) NULL AFTER `update_time`;

2、实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    //id 对应数据库中的主键 (uuid、自增id、雪花算法、redis、zookeeper)
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;

    @TableField(fill = FieldFill.INSERT )
    private Date createTime;//数据库中的字段是 create_time  因可以自动识别驼峰
    @TableField(fill = FieldFill.INSERT_UPDATE )
    private Date updateTime;


    @Version //乐观锁Version 注解
    private Integer version; // 乐观锁
}

3、新增config文件 MyBatisPlusConfig.java

//扫描包也可以放在这里,不需要再发到主启动类中了
//扫描 mapper文件
@MapperScan("com.p.mybatis_plus.mapper")
@EnableTransactionManagement // 自动管理事务
@Configuration //配置类
public class MyBatisPlusConfig {

    // 注册乐观所插件
    @Bean //注意这里
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
}

4、测试

//乐观锁测试成功
    @Test
    public void testLockerInterceptor(){
        //1、查询用户信息
        User user = userMapper.selectById(1L);
        // 2、修改用户信息
        user.setName("P");
        user.setEmail("123456789");
        //3、执行更新操作
        userMapper.updateById(user);
    }

结果

==>  Preparing: UPDATE user SET name=?, age=?, email=?, update_time=?, version=? WHERE id=? AND version=? 
==> Parameters: P(String), 18(Integer), 123456789(String), 2022-10-09 16:44:16.963(Timestamp), 2(Integer), 1(Long), 1(Integer)
<==    Updates: 1

失败测试

//乐观锁测试失败
    @Test
    public void testLockerInterceptor2(){
        //线程1
        User user = userMapper.selectById(1L);
        user.setName("P1111");
        user.setEmail("123456789");
        //线程2
        User user2 = userMapper.selectById(1L);
        user2.setName("P2222");
        user2.setEmail("123456789");
        userMapper.updateById(user2);


        userMapper.updateById(user); // 如果没有乐观锁就会覆盖插队线程的值
    }

结果

==>  Preparing: UPDATE user SET name=?, age=?, email=?, update_time=?, version=? WHERE id=? AND version=? 
==> Parameters: P2222(String), 18(Integer), 123456789(String), 2022-10-09 16:47:12.603(Timestamp), 4(Integer), 1(Long), 3(Integer)
<==    Updates: 1

 // 此时会发现 这里的修改次数为0 说明数据库中并没有更改第一个值   
==>  Preparing: UPDATE user SET name=?, age=?, email=?, update_time=?, version=? WHERE id=? AND version=? 
==> Parameters: P1111(String), 18(Integer), 123456789(String), 2022-10-09 16:47:12.656(Timestamp), 4(Integer), 1(Long), 3(Integer)
<==    Updates: 0

   // 数据库中的值
    id  name    age   password        create_time    update_time  version
    1   P2222   18  123456789       2022-10-09     16:47:12        4

查询操作

测试

public void selectTest(){
        //根据id查询
        User user = userMapper.selectById(1L);
        System.out.println(user);

        //查询多个用户  批量查询
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        users.forEach(System.out::println);

        //条件查询 map
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","P");
        List<User> users1 = userMapper.selectByMap(map);
        users1.forEach(System.out::println);
    }

结果

//根据id查询
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id=? 
==> Parameters: 1(Long)
<==    Columns: id, name, age, email, create_time, update_time, version
<==        Row: 1, P2222, 18, 123456789, null, 2022-10-09 16:47:12, 4
<==      Total: 1


// 批量查询
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id IN ( ? , ? , ? ) 
==> Parameters: 1(Integer), 2(Integer), 3(Integer)
<==    Columns: id, name, age, email, create_time, update_time, version
<==        Row: 1, P2222, 18, 123456789, null, 2022-10-09 16:47:12, 4
<==        Row: 2, Jack, 20, test2@baomidou.com, null, null, 1
<==        Row: 3, Tom, 28, test3@baomidou.com, null, null, 1
<==      Total: 3

//条件查询 map
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE name = ? 
==> Parameters: P(String)
<==    Columns: id, name, age, email, create_time, update_time, version
<==        Row: 1578286574218575874, P, 12, 123, null, null, 1
<==        Row: 1578286574218575875, P, 120, 123, 2022-10-09 15:10:04, 2022-10-09 15:10:04, 1
<==      Total: 2

分页查询

1、原始的limit进行分页

2、pageHelper第三方插件

3、MybatisPlus内置了分页插件

使用

1、配置拦截器组件 config

  //分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }

2、直接使用Page对象即可

//测试分页查询
    @Test
    public void testPage(){
        //                               当前页      页面大小
        Page<User> page = new Page<>(1, 5);
        userMapper.selectPage(page,null);
        page.getRecords().forEach(System.out::println);
        System.out.println(page.getTotal()); //获取数据总数
    }

3、结果

==>  Preparing: SELECT COUNT(1) FROM user 
==> Parameters: 
<==    Columns: COUNT(1)
<==        Row: 7     // 总数的查询
==>  Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user LIMIT 0,5 
==> Parameters: 
<==    Columns: id, name, age, email, create_time, update_time, version
<==        Row: 1, P2222, 18, 123456789, null, 2022-10-09 16:47:12, 4
<==        Row: 2, Jack, 20, test2@baomidou.com, null, null, 1
<==        Row: 3, Tom, 28, test3@baomidou.com, null, null, 1
<==        Row: 4, Sandy, 21, test4@baomidou.com, null, null, 1
<==        Row: 5, Billie, 24, test5@baomidou.com, null, null, 1
<==      Total: 5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b5ac798]
User(id=1, name=P2222, age=18, email=123456789, createTime=null, updateTime=Sun Oct 09 16:47:12 CST 2022, version=4)
User(id=2, name=Jack, age=20, email=test2@baomidou.com, createTime=null, updateTime=null, version=1)
User(id=3, name=Tom, age=28, email=test3@baomidou.com, createTime=null, updateTime=null, version=1)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com, createTime=null, updateTime=null, version=1)
User(id=5, name=Billie, age=24, email=test5@baomidou.com, createTime=null, updateTime=null, version=1)

删除操作

测试

//测试删除
    @Test
    public void deletTest(){
        //根据id删除
        userMapper.deleteById(1578286574218575874L);

        //根据id 批量删除
        userMapper.deleteBatchIds(Arrays.asList(1578286574218575874L,1578286574218575875L));

        //通过map删除
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","P");
        userMapper.deleteByMap(map);
    }

在工作会遇到一些问题:逻辑删除

逻辑删除

物理删除:从数据库中直接删除

逻辑删除:在数据库中没有被移除,而是通过一个变量来让他失效

管理员可以查看被删除的记录! 防止数据的丢失,类似于回收站

测试

ALTER TABLE `user`
ADD COLUMN `deleted`  int(255) NULL COMMENT '逻辑删除' AFTER `deleted`;

2、pojo

@TableLogic //逻辑删除注解
 private Integer deleted;

3、添加config 插件 高版本不需要配置插件,具体看官网

//逻辑删除组件
    @Bean
    public ISqlInjector sqlInjector(){
        return new LogicSqlInjector();
    }

4、配置properties

# 配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=0  # 删除后
mybatis-plus.global-config.db-config.logic-not-delete-value=1  # 未删除,默认为1 

5、测试

 //根据id删除
 userMapper.deleteById(1578286574218575874L);

6、结果 删除操作,实际为 更新操作

==>  Preparing: UPDATE user SET deleted=0 WHERE id=? AND deleted=1 
==> Parameters: 1578286574218575874(Long)
<==    Updates: 1

7、测试查询是否可以查出 会自动拼接 deleted =1 的条件,并不能查出来

==>  Preparing: SELECT id,name,age,email,create_time,update_time,version,deleted FROM user WHERE id=? AND deleted=1 
==> Parameters: 1578286574218575874(Long)
<==      Total: 0

性能分析插件

平时的开发中,会遇到一些慢sql。测试 drd。。

作用:性能分析拦截器,用于输出每条SQL语句及其执行时间

MP也提供了性能分析插件,如果超过这个时间就停止运行!

1、导入插件

//性能分析插件
    @Bean
    @Profile({"dev","test"}) // 设置dev test 环境开启,保证我们的效率
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(100);// 默认单位ms  设置sql执行的最大时间,如果超过了就不执行
        performanceInterceptor.setFormat(true); //是否格式化SQL语句
        return performanceInterceptor;
    }

2、properties中配置环境

# 设置开发环境
spring.profiles.active=dev

3、测试使用 超出规定时间,就会报出异常!

条件构造器

Wrapper

写一些复杂的sql就可以使用它来替代!

测试一

@Test
    void test1(){
        //查询name不为空,email不为空, 年龄大于等于12
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")  //name不为空
                .isNotNull("email") //email不为空
                .ge("age",12); //g大于  e等于
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

测试二

@Test
public void testWrapper2() {
    //查询name=P的用户
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("name","p");
    //查询一个数据selectOne,若查询出多个会报错
    //Expected one result (or null) to be returned by selectOne(), but found: *
    //若出现多个结果使用list或map
    User user = userMapper.selectOne(wrapper);//查询一个数据,若出现多个结果使用list或map
    System.out.println(user);
}

测试三

@Test
public void testWrapper3() {
    //查询age在10-20之间的用户
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age", 10, 20);//区间
    Integer count = userMapper.selectCount(wrapper);//输出查询的数量selectCount
    System.out.println(count);
}

测试四

@Test
public void testWrapper4() {
    //模糊查询
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper
        .notLike("name","s") // %s%  %占位符
        .likeRight("email","t");// t%  以t开头的字符 
    List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
    maps.forEach(System.out::println);
}

测试五

@Test
public void testWrapper5() {
    //模糊查询
    // SELECT id,name,age,email,version,deleted,create_time,update_time 
    //FROM user 
    //WHERE deleted=0 AND id IN 
    //(select id from user where id<5)

    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //id 在子查询中查出来
    wrapper.inSql("id","select id from user where id<5");
    List<Object> objects = userMapper.selectObjs(wrapper);
    objects.forEach(System.out::println);
}

测试六

@Test
public void testWrapper6() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //通过id进行降序排序
    wrapper.orderByDesc("id");
    List<User> userList = userMapper.selectList(wrapper);
    userList.forEach(System.out::println);
}

Mysql => JDBC => Mybatis => MybatisPlus

代码自动生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

直接放在Test测试中运行

package com.wsk;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
//代码自动生成器
public class WskCode {
    public static void main(String[] args) {
        //我们需要构建一个代码生成器对象
        AutoGenerator mpg = new AutoGenerator();
        //怎么样去执行,配置策略
        //1、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");//获取当前目录
        gc.setOutputDir(projectPath+"/src/main/java");//输出到哪个目录
        gc.setAuthor("wsk");// 生成作者名字
        gc.setOpen(false);//是否打开文件夹
        gc.setFileOverride(false);//是否覆盖原来生成的代码
        gc.setServiceName("%sService");//去Service的接口的I前缀
        gc.setIdType(IdType.ID_WORKER);//默认初始的算法
        gc.setDateType(DateType.ONLY_DATE);//日期的类型
        gc.setSwagger2(true);//是否生成swagger2文档
        mpg.setGlobalConfig(gc);
        //2、设置数据源 连接数据库
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUsername("root");
        dsc.setPassword("root");
        dsc.setUrl("jdbc:mysql://localhost:3306/wuye?useSSL=false&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);
        //3、包的配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("blog");//模块的名
        pc.setParent("com.p");//放在那个包下
        pc.setEntity("pojo");//实体类的名字
        pc.setMapper("mapper");//设置mapper类名
        pc.setService("service");//service类名
        pc.setController("controller");//controller类名
        mpg.setPackageInfo(pc);
        //4、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("admin","danyuan","building","room");//设置要映射的表名,只需改这里即可,如:数据库中有admin表,可以隐射到admin表
        strategy.setNaming(NamingStrategy.underline_to_camel);//设置包的命名规则,下划线转驼峰命名
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//设类的命名规则,下划线转驼峰
        strategy.setEntityLombokModel(true);//是否使用lombok开启注解
        strategy.setLogicDeleteFieldName("deleted");//逻辑删除,因有逻辑删除所有需要自动填充
        //自动填充配置
        TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);//insert操作
        TableFill gmtUpdate = new TableFill("gmt_update", FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();//new一个list集合
        tableFills.add(gmtCreate);
        tableFills.add(gmtUpdate);
        strategy.setTableFillList(tableFills);//需要传入list类型
        //乐观锁配置
        strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);//开启驼峰命名
        strategy.setControllerMappingHyphenStyle(true);//访问地址:变成localhost:8080/hello_id_2来访问,url路径下划线
        mpg.setStrategy(strategy);
        mpg.execute();//执行
    }
}

依赖

<!--模板引擎 依赖:mybatis-plus代码生成的时候报异常-->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.0</version>
</dependency>
<!--配置ApiModel在实体类中不生效-->
<dependency>
    <groupId>com.spring4all</groupId>
    <artifactId>spring-boot-starter-swagger</artifactId>
    <version>1.5.1.RELEASE</version>
</dependency>
<!--freemarker-->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.30</version>
</dependency>
<!--beetl-->
<dependency>
    <groupId>com.ibeetl</groupId>
    <artifactId>beetl</artifactId>
    <version>3.3.2.RELEASE</version>
</dependency>