MyBatis-Plus

MyBatis-Plus

01. 概述

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

• 官网:https://mybatis.plus/ 或 https://mp.baomidou.com/

在这里插入图片描述

版本

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>3.4.0</version>
</dependency>

在这里插入图片描述

02. 快速入门

SpringBoot 整合 MyBatis-Plus,并实现根据Id查询功能。

2.1 数据库环境准备

创建一个数据库,导入部分数据

2.2 引入相关依赖

创建maven工程 springboot-mp(创建启动类、yml文件这里不再赘述),编写pom文件如下

<!-- 指定SpringBoot父工程-->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.6.RELEASE</version>
</parent>

<groupId>com.darzen</groupId>
<artifactId>springboot-mp</artifactId>
<version>1.0-SNAPSHOT</version>


<dependencies>
    
    <!--mybatisplus启动器,传递依赖了JDBC启动器-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.0</version>
    </dependency>
    
    <!--mysql驱动,覆盖父工程的版本号-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>

    <!-- 测试启动器-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

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

2.3 编写DataSource相关配置

resources目录下创建application.yml配置文件

# datasource
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mp # localhost:3306改成自己的数据库地址
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver

2.4 编码

实体类


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

/**
 * 用户实体类
 */
@TableName("tb_user") // 指定表名
@Data
public class User {
    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String email;
}

mapper数据访问层



import cn.itcast.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * 使用mp定义Mapper,需要让Mapper接口继承 BaseMapper接口。
 */
public interface UserMapper extends BaseMapper<User> {
}

启动类增加 @MapperScan 注解



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

/**
 * 启动类

 */
@MapperScan(basePackages = {"cn.darzen.dao"}) // 指定mapper包路径
@SpringBootApplication
public class MybatisPlusSpringbootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusSpringbootApplication.class, args);
    }
}

2.5 测试

单元测试类



import cn.itcast.dao.UserMapper;
import cn.itcast.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * 用户数据访问层单元测试类

 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @Autowired
    private UserMapper userMapper;


    /**
     * 根据id查询用户
     */
    @Test
    public void testSelectById(){
        User user = userMapper.selectById(1l);
        System.out.println("user = " + user);
    }
}

运行结果

user = User(id=1, userName=zhangsan, password=123456, name=张三, age=18, email=test1@itcast.cn)

03. 通用CRUD-新增

在这里插入图片描述

3.1 改造实体类

/**
 * 实体类的属性名和数据库的字段名自动映射:
 * 1.名称一样
 * 2.数据库字段使用_分割,实体类属性名使用驼峰名称
 */
@TableName("tb_user")
@Data
public class User {

    // 设置id生成策略:AUTO,数据库主键自增
    @TableId(type = IdType.AUTO)
    private Long id;
    // @TableField("user-name")
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String email;

   // 不希望该值存入数据库
   @TableField(exist = false)
   private String info;

}

3.2 @TableField注解说明

1)  @TableField("user_name") 指定映射关系
实体类的属性名和数据库的字段名自动映射:
	* 名称一样
	* 数据库字段使用_分割,实体类属性名使用驼峰名称
否则需要使用 @TableField("user_name") 指定映射关系

2)  忽略某个字段的查询和插入
	@TableField(exist = false) 

3)  设置id生成策略:AUTO 数据库主键自增
    @TableId(type = IdType.AUTO)

3.3 属性配置说明

mybatis-plus:
  global-config:
    db-config:
      # 表名前缀,设置后,如果数据库表名是tb_user, 那么实体类上可以不添加@TableName注解,不建议这里统一设置
      table-prefix: tb_
      # 全局默认主键类型,设置后,即可省略实体对象中的@TableId(type = IdType.AUTO)配置, 不建议这里统一设置
      id-type: auto 
  configuration:
    # 日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.4 单元测试

测试用例

/**
 * 新增用户
 */
@Test
public void testInsert(){
    User user = new User();
    user.setUserName("zhuge");
    user.setName("诸葛孔明");
    user.setPassword("123456");
    user.setInfo("三国之卧龙"); // 不会保存到数据库,因为在实体类设置了@TableField(exist = false)

    userMapper.insert(user);
}

运行结果

==>  Preparing: INSERT INTO tb_user ( user_name, password, name ) VALUES ( ?, ?, ? )
==> Parameters: zhuge(String), 123456(String), 诸葛孔明(String)
<==    Updates: 1

04. 通用CRUD-删除

在这里插入图片描述

4.1 根据id删除

测试用例


/**
 * 根据id删除用户,删除id为6的数据
 */
@Test
public void testDeleteById(){
    // 返回值代表删除成功的记录数
    int count = userMapper.deleteById(6l);
}

运行结果

==>  Preparing: DELETE FROM tb_user WHERE id=?
==> Parameters: 6(Long)
<==    Updates: 1

4.2 根据id集合批量删除

测试用例

/**
 * 根据ID集合批量删除,删除id为4、5的数据
 */
@Test
public void testDeleteByBatchIds(){
    List<Long> ids = new ArrayList();
    ids.add(4l);
    ids.add(5l);

    // 返回值代表删除成功的记录数
    int count = userMapper.deleteBatchIds(ids);
}

运行结果

==>  Preparing: DELETE FROM tb_user WHERE id IN ( ? , ? )
==> Parameters: 4(Long), 5(Long)
<==    Updates: 2

4.3 根据map条件删除

测试用例

/**
 * 根据Map条件删除,删除user_name为zhangsan 且 年龄为18的数据
 */
@Test
public void testDeleteByMap(){
    Map<String, Object> params = new HashMap<>();
    // key-代表数据库字段名, value-匹配的值
    // 注意:map中如果put多个判断条件,默认以and连接
    params.put("user_name", "zhangsan"); // 相当于where user_name = 'zhangsan'
    params.put("age", 18);

    // count代表删除成功的记录数
    int count = userMapper.deleteByMap(params);
}

运行结果

==>  Preparing: DELETE FROM tb_user WHERE user_name = ? AND age = ?
==> Parameters: zhangsan(String), 18(Integer)
<==    Updates: 1

4.4 根据条件构造器删除

问题:如果条件比较复杂,where条件有like、in、or等条件呢?就可以根据条件构造器QueryWrapper删除了

单元测试

/**
 * 根据条件构造器删除
 */
@Test
public void testDeleteByWrapper(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // 参数1-字段名,参数2-匹配的值
    wrapper.eq("user_name", "lisi");
    	
    // count代表删除成功的记录数
    int count = userMapper.delete(wrapper);

}

运行结果

==>  Preparing: DELETE FROM tb_user WHERE (user_name = ?)
==> Parameters: lisi(String)
<==    Updates: 1

05. 通用CRUD-更新

在这里插入图片描述

5.1 根据id更新

由于之前的数据不多了,操作之前可以先把数据库表删了,再重新执行以下sql脚本,或者自己手动添加新数据亦可。

测试用例

/**
 * 根据id更新,将id为1的数据,年龄改为100
 */
@Test
public void testUpdateById(){
    User user = new User();
    user.setId(1l); // 必须设置,因为是根据id更新
    user.setAge(100); // 修改后的值

    // 修改成功的记录数
    int count = userMapper.updateById(user);
}

运行结果

==>  Preparing: UPDATE tb_user SET age=? WHERE id=?
==> Parameters: 100(Integer), 1(Long)
<==    Updates: 1

5.2 根据条件构造器更新

测试用例

/**
 * 根据条件构造器更新, 将user_name为zhangsan的name改为司马懿,age改为60
 */
@Test
public void testUpdateByWrapper() {
    // user对象为修改后的值
    User user = new User();
    user.setName("司马懿");
    user.setAge(60);

    // where条件
    UpdateWrapper<User> updateWrapper = new UpdateWrapper();
    updateWrapper.eq("user_name", "zhangsan");

    int count = userMapper.update(user, updateWrapper);
}

运行结果

==>  Preparing: UPDATE tb_user SET name=?, age=? WHERE (user_name = ?)
==> Parameters: 司马懿(String), 60(Integer), zhangsan(String)
<==    Updates: 1

06. 通用CRUD-查询

在这里插入图片描述

查询相关API非常多,有根据ID查询、根据ID批量查询、根据条件构造器查询、根据Map条件查询,分页查询、查询总记录数等等…

6.1 基本比较查询

语法

eq( ) :  等于 =
ne( ) :  不等于 <>
gt( ) :  大于 >
ge( ) :  大于等于 >=
lt( ) :  小于 <
le( ) :  小于等于 <=
between ( ) :  BETWEEN 值1 AND 值2 
notBetween ( ) :  NOT BETWEEN 值1 AND 值2 
in( ) :  in
notIn( ) :  not in

测试用例

/**
 * 基本比较查询: where user_name = 'lisi' and age < 23 and name in ('李四', '王五')
 */
@Test
public void testWrapper1(){
    // 创建查询条件构造器
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    // 设置查询条件,多个条件之间默认以and连接
    queryWrapper.eq("user_name", "lisi")
        .lt("age", 23)
        .in("name", "李四", "王五");

    // select * from tb_user where user_name = 'lisi' and age < 23 and name in ('李四', '王五')
    List<User> userList = userMapper.selectList(queryWrapper);
    for (User user : userList) {
        System.out.println("user = " + user);
    }
}

运行结果

==>  Preparing: SELECT id,user_name,password,name,age,email FROM tb_user WHERE (user_name = ? AND age < ? AND name IN (?,?))
==> Parameters: lisi(String), 23(Integer), 李四(String), 王五(String)
<==    Columns: id, user_name, password, name, age, email
<==        Row: 2, lisi, 123456, 李四, 20, test2@itcast.cn
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7abe27bf]
user = User(id=2, userName=lisi, password=123456, name=李四, age=20, email=test2@itcast.cn, info=null)

6.2 逻辑查询

语法

and 参数为Consumer lamboda表达式,用于隔离多组条件
or 后面接其他条件(基本比较查询的条件)

测试用例一

/**
 * 逻辑查询-or:查询 user_name = lisi 或 age > 10
 */
@Test
public void testLogicOr(){
    // 创建查询条件构造器
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    // 设置查询条件
    queryWrapper.eq("user_name", "lisi")
                .or() // 不加or默认是以and连接多个条件
                .gt("age", 10);


    // select * from tb_user where user_name = 'lisi' or age > 10
    List<User> userList = userMapper.selectList(queryWrapper);
    for (User user : userList) {
        System.out.println("user = " + user);
    }
}

运行结果一

==>  Preparing: SELECT id,user_name,password,name,age,email FROM tb_user WHERE (user_name = ? OR age > ?)
==> Parameters: lisi(String), 10(Integer)
<==    Columns: id, user_name, password, name, age, email
<==        Row: 1, zhangsan, 123456, 司马懿, 60, test1@itcast.cn
<==        Row: 2, lisi, 123456, 李四, 20, test2@itcast.cn
<==        Row: 3, wangwu, 123456, 王五, 28, test3@itcast.cn
<==        Row: 4, zhaoliu, 123456, 赵六, 21, test4@itcast.cn
<==        Row: 5, sunqi, 123456, 孙七, 24, test5@itcast.cn
<==      Total: 5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@796065aa]
user = User(id=1, userName=zhangsan, password=123456, name=司马懿, age=60, email=test1@itcast.cn, info=null)
user = User(id=2, userName=lisi, password=123456, name=李四, age=20, email=test2@itcast.cn, info=null)
user = User(id=3, userName=wangwu, password=123456, name=王五, age=28, email=test3@itcast.cn, info=null)
user = User(id=4, userName=zhaoliu, password=123456, name=赵六, age=21, email=test4@itcast.cn, info=null)
user = User(id=5, userName=sunqi, password=123456, name=孙七, age=24, email=test5@itcast.cn, info=null)

测试用例二

/**
 * 逻辑查询-and:查询 age > 23 and (name=王五 or name = 李四)
 */
@Test
public void testLogicAnd(){
    // 创建查询条件构造器
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    
    // 设置查询条件
    queryWrapper.gt("age", 23)
            // 相当于and (), ()中可指定多个条件
            .and(i -> i.eq("name", "王五").or().eq("name", "李四"));

    // select * from tb_user where user_name = 'lisi' and (name = '王五' or name = '李四')
    List<User> userList = userMapper.selectList(queryWrapper);
    for (User user : userList) {
        System.out.println("user = " + user);
    }
}

运行结果二

==>  Preparing: SELECT id,user_name,password,name,age,email FROM tb_user WHERE (age > ? AND (name = ? OR name = ?))
==> Parameters: 23(Integer), 王五(String), 李四(String)
<==    Columns: id, user_name, password, name, age, email
<==        Row: 3, wangwu, 123456, 王五, 28, test3@itcast.cn
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@47f08b81]
User(id=3, userName=wangwu, password=123456, name=王五, age=28, email=test3@itcast.cn, info=null)

6.3 模糊查询

语法

like 相当于 like '%关键字%'
notLike 相当于 not like '%关键字%'
likeLeft 相当于 like '%关键字'
likeRight 相当于 like '关键字%'

测试用例

/**
 * 模糊查询:user_name like 'zhang%'
 */
@Test
public void testLike(){
    // 1.创建查询条件构建器
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // 2.设置条件
    wrapper.likeRight("user_name", "zhang");

    // SELECT * from tb_user where user_name like 'zhang%'
    List<User> userList = userMapper.selectList(wrapper);
    for (User user : userList) {
        System.out.println("user = " + user);
    }
}

运行结果

==>  Preparing: SELECT id,user_name,password,name,age,email FROM tb_user WHERE (user_name LIKE ?)
==> Parameters: zhang%(String)
<==    Columns: id, user_name, password, name, age, email
<==        Row: 1, zhangsan, 123456, 司马懿, 60, test1@itcast.cn
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3d36dff4]
user = User(id=1, userName=zhangsan, password=123456, name=司马懿, age=60, email=test1@itcast.cn, info=null)

6.4 排序查询

语法

orderBy : 指定排序规则
orderByAsc : 升序排序
orderByDesc : 降序排序

测试用例

/**
 * 排序:查询年龄小于50并且根据年龄升序排序
 */
@Test
public void testOrder() {
    // 1.创建查询条件构建器
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // 2.设置条件
    wrapper.lt("age", 50)
        // 参数1:是否要作为排序条件(肯定为true啦),参数2-是否升序(true为升序),参数3-排序字段名
        .orderBy(true, true, "age");

    // select * from tb_user where age < 50 order by age asc
    List<User> userList = userMapper.selectList(wrapper);
    for (User user : userList) {
        System.out.println("user = " + user);
    }
}

运行结果

==>  Preparing: SELECT id,user_name,password,name,age,email FROM tb_user WHERE (age < ?) ORDER BY age ASC
==> Parameters: 50(Integer)
<==    Columns: id, user_name, password, name, age, email
<==        Row: 2, lisi, 123456, 李四, 20, test2@itcast.cn
<==        Row: 4, zhaoliu, 123456, 赵六, 21, test4@itcast.cn
<==        Row: 5, sunqi, 123456, 孙七, 24, test5@itcast.cn
<==        Row: 3, wangwu, 123456, 王五, 28, test3@itcast.cn
<==      Total: 4
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7abe27bf]
user = User(id=2, userName=lisi, password=123456, name=李四, age=20, email=test2@itcast.cn, info=null)
user = User(id=4, userName=zhaoliu, password=123456, name=赵六, age=21, email=test4@itcast.cn, info=null)
user = User(id=5, userName=sunqi, password=123456, name=孙七, age=24, email=test5@itcast.cn, info=null)
user = User(id=3, userName=wangwu, password=123456, name=王五, age=28, email=test3@itcast.cn, info=null)

6.5 select

问题:查询相关API默认是返回所有字段,相当于select * from 表名,若想要指定返回的字段就可以使用select API。

/**
 * 测试select字段
 */
@Test
public void testSelect(){
    // 1.创建查询条件构建器
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // 2.设置条件
    wrapper.lt("age", 50)
            .orderBy(true, true, "age")
            .select("user_name", "age"); // 指定要返回的字段


    List<User> userList = userMapper.selectList(wrapper);
    for (User user : userList) {
        System.out.println(user);
    }
}

运行结果

==>  Preparing: SELECT user_name,age FROM tb_user WHERE (age < ?) ORDER BY age ASC
==> Parameters: 50(Integer)
<==    Columns: user_name, age
<==        Row: lisi, 20
<==        Row: zhaoliu, 21
<==        Row: sunqi, 24
<==        Row: wangwu, 28
<==      Total: 4
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7abe27bf]
user = User(id=null, userName=lisi, password=null, name=null, age=20, email=null, info=null)
user = User(id=null, userName=zhaoliu, password=null, name=null, age=21, email=null, info=null)
user = User(id=null, userName=sunqi, password=null, name=null, age=24, email=null, info=null)
user = User(id=null, userName=wangwu, password=null, name=null, age=28, email=null, info=null)

从运行结果可以看出,只返回user_name和age字段

6.6 分页查询

编写配置类,添加拦截器


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

@Configuration
public class PageConfig {

    /**
     * 3.4.0之前的版本用这个
     * @return
     */
    
    /* 
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return  new PaginationInterceptor();
    }
    */

    /**
     * 3.4.0之后提供的拦截器的配置方式
     * @return
     */
   @Bean
   public MybatisPlusInterceptor mybatisPlusInterceptor(){
       MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
       mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
       return mybatisPlusInterceptor;
   }
}

编写单元测试类

/**
 * 分页查询
 */
@Test
public void testPage(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.lt("age", 50)
            .orderBy(true, true, "age")
            .select("user_name", "age"); // 指定要返回的字段

    // 参数1-当前页,参数2-每页显示数
    Page<User> page = new Page<User>(1, 2); // 查询第一页,每页显示2条

    Page<User> result = userMapper.selectPage(page, wrapper);

    List<User> records = result.getRecords(); // 用户数据
    System.out.println("总条数 = " + result.getTotal());
    System.out.println("总页数 = " + result.getPages());

    for (User user : records) {
        System.out.println(user);
    }

}

运行结果

==>  Preparing: SELECT COUNT(1) FROM tb_user WHERE (age < ?)
==> Parameters: 50(Integer)
<==    Columns: COUNT(1)
<==        Row: 4
<==      Total: 1
==>  Preparing: SELECT user_name,age FROM tb_user WHERE (age < ?) ORDER BY age ASC LIMIT ?
==> Parameters: 50(Integer), 2(Long)
<==    Columns: user_name, age
<==        Row: lisi, 20
<==        Row: zhaoliu, 21
<==      Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@383f1975]
总条数 = 4
总页数 = 2
User(id=null, userName=lisi, password=null, name=null, age=20, email=null, info=null)
User(id=null, userName=zhaoliu, password=null, name=null, age=21, email=null, info=null)

07. 使用原生mybatis

**问题:**上面讲解的API 都是Mybatis Plus对于单表CRUD进行的封装,那在实际开发中,可能存在复杂sql的编写,例如:多表联查,子查询等等,此类操作就需要开发人员使用原生Mybatis的功能,自己写sql语句了。

7.1 基本使用

第一步:yml文件中配置相关属性

mybatis-plus:
  global-config:
    db-config:
      # 全局设置自增,设置后,实体类中不需要通过@TableId()
      id-type: auto
      table-prefix: tb_
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印sql
    # 设置sql返回字段驼峰转换
    map-underscore-to-camel-case: true
  # 指定xml文件路径
  mapper-locations:
    - classpath:/mappers/*.xml
  # 返回值别名包路径
  type-aliases-package: cn.darzen.pojo

第二步:resoures目录下创建mappers文件夹,然后在mappers文件夹下创建UserMapper.xml文件(可使用插件J2EECfgFile插件)

在这里插入图片描述

第三步:编写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">
<!--指定userMapper接口的路径-->
<mapper namespace="cn.darzen.dao.UserMapper">

	<select id="findById" resultType="User">
		select * from tb_user where id = #{id}
	</select>
</mapper>

第四步:编写UserMapper.java接口



import cn.darzen.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * 使用mp定义Mapper,需要让Mapper接口继承 BaseMapper接口。
 */
public interface UserMapper extends BaseMapper<User> {

    /**
     * 根据id查询用户
     * @param id
     * @return
     */
    public User findById(Long id);
}

第五步:编写单元测试用例

/**
 * 测试自定义sql
 */
@Test
public void testFindById(){
    User user = userMapper.findById(1l);
    System.out.println("user = " + user);
}

运行结果

==>  Preparing: select * from tb_user where id = ?
==> Parameters: 1(Long)
<==    Columns: id, user_name, password, name, age, email
<==        Row: 1, zhangsan, 123456, 司马懿, 60, test1@itcast.cn
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@40368a46]
user = User(id=1, userName=zhangsan, password=123456, name=司马懿, age=60, email=test1@itcast.cn, info=null)

7.2 分页查询

问题:使用原生的mybatis功能,如何加入Mybatis Plus的分页?

第一步:编写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">
<!--指定userMapper接口的路径-->
<mapper namespace="cn.itcast.dao.UserMapper">

   <select id="findById" resultType="User">
      select * from tb_user where id = #{id}
   </select>

   <!--分页查询-->
   <select id="selectByPage" resultType="User">
      select * from tb_user where age &gt; #{lowerNum}
   </select>

</mapper>

第二步:编写UserMapper.java接口,添加方法

/**
 * 分页查询
 * @param page
 * @param lowerNum:最小值
 * @return
 */
public Page<User> selectByPage(Page page, @Param("lowerNum") int lowerNum);

第三步:编写单元测试用例

/**
 * 测试自定义分页查询
 */
@Test
public void testSelectByPage(){
    // 定义分页对象
    Page<User> page = new Page<>(1, 2);

    page = userMapper.selectAllByPage(page, 0);

    List<User> records = page.getRecords(); // 返回用户数据
    long total = page.getTotal(); // 总条数
    long pages = page.getPages(); // 总页数

    for (User user : records) {
        System.out.println("user = " + user);
    }
    System.out.println("总条数 = " + total);
    System.out.println("总页数 = " +pages);
}

运行结果

==>  Preparing: SELECT COUNT(1) FROM tb_user WHERE age > ?
==> Parameters: 0(Integer)
<==    Columns: COUNT(1)
<==        Row: 5
<==      Total: 1
==>  Preparing: select * from tb_user where age > ? LIMIT ?
==> Parameters: 0(Integer), 2(Long)
<==    Columns: id, user_name, password, name, age, email
<==        Row: 1, zhangsan, 123456, 张三, 18, test1@itcast.cn
<==        Row: 2, lisi, 123456, 李四, 20, test2@itcast.cn
<==      Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@476a736d]
user = User(id=1, userName=zhangsan, password=123456, name=张三, age=18, email=test1@itcast.cn, info=null)
user = User(id=2, userName=lisi, password=123456, name=李四, age=20, email=test2@itcast.cn, info=null)
总条数 = 5
总页数 = 3

08. 通用枚举(了解)

1)为什么使用通用枚举?

目前的实体类这样设计

@Data
@TableName("tb_user") // 指定表名
public class User {
    private Long id;
    private String userName;
    
    // 性别 1: 男 2: 女
    private Integer sex;    
}

那么最终获取到的JSON数据应该类似于这样:

{
    "id":100,
    "userName":"jack",
    "sex":1
}

如若使用MyBatis-Plus的枚举自动关联注入,可以更优雅的实现如下效果

{
    "id":100,
    "userName":"jack",
    "sex":"男"
}
2)实现步骤

第一步:修改表结构

ALTER TABLE `tb_user` ADD COLUMN `sex` int(1) NULL DEFAULT 1 COMMENT '1-男,2-女';

第二步:定义枚举类


import com.baomidou.mybatisplus.annotation.IEnum;

/**
 * 性别枚举类
 */
public enum SexEnum implements IEnum<Integer> {

    MAN(1, "男"),
    WOMEN(2, "女");

    private int value;
    private String desc;

    SexEnum(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }

    @Override
    public Integer getValue() {
        return this.value;
    }

    @Override
    public String toString() {
        return this.desc;
    }
}

第三步:修改yml配置,扫描枚举类所在包

mybatis-plus:
  global-config:
    db-config:
      # 全局设置自增,设置后,实体类中不需要通过@TableId()
      id-type: auto
      table-prefix: tb_
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印sql
    # 设置sql返回字段驼峰转换
    map-underscore-to-camel-case: true
  # 指定xml文件路径
  mapper-locations:
    - classpath:/mappers/*.xml
  # 返回值别名包路径
  type-aliases-package: cn.darzen.pojo
  # 指定枚举类包路径
  type-enums-package: cn.darzen.enums

第四步:修改实体类,增加性别字段

@TableField(value = "sex")
private SexEnum sex;
3)测试

查询测试

/**
 * 测试通用枚举-查询
 */
@Test
public void testEnum1(){
    // 参数为null代表无查询条件
    List<User> users = userMapper.selectList(null);

    for (User user : users) {
        System.out.println("user = " + user);
    }
}

数据库数据:

在这里插入图片描述

运行结果:

在这里插入图片描述

从上图可以看出,查询时自动将数据库的数据由 1 转为了 男(会使用枚举类的重写的toString方法返回值)。

新增测试

/**
 * 测试通用枚举-新增
 */
@Test
public void testEnum2(){
    User user = new User();
    user.setName("赵子龙");
    user.setAge(18);
    user.setUserName("zhaozilong");
    user.setPassword("123456");
    user.setEmail("1111@sina.com");
    user.setSex(SexEnum.MAN); // 使用枚举值

    userMapper.insert(user);
}

数据库数据:

在这里插入图片描述

运行结果:

在这里插入图片描述

上图可以看出,当插入数据时,会将枚举值转换为1,也就是枚举类中的value属性值

09. service 封装(了解)

Mybatis-Plus 为了开发更加快捷,对业务层也进行了封装,直接提供了相关的接口和实现类。我们在进行业务层开发时,可以继承它提供的接口和实现类,使得编码更加高效。

步骤

  1. 定义接口继承IService

  2. 定义实现类继承ServiceImpl<Mapper,Entity> 实现定义的接口

定义Service接口



import cn.itcast.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;

public interface UserService extends IService<User> {
    
}

定义Service实现类



import cn.darzen.dao.UserMapper;
import cn.darzen.pojo.User;
import cn.darzen.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    /**
     * test
     */
    public void test(){
        // this.baseMapper可以获取到userMapper对象,相当于已经注入进来了并且放到了this.baseMapper中;
        // 说明:Iservice中也包含了一些封装的CRUD方法
        UserMapper baseMapper = this.baseMapper;
    }
}

调用Service示例

在这里插入图片描述

项目结构:

在这里插入图片描述

10. 自动填充(了解)

介绍

我们在进行数据库表的更新/插入操作时,如果有创建时间、更新时间,每次插入都需要手动设置字段值,这就很麻烦。而Mybatis Plus提供了自动填充字段的设置。即给某些指定字段设置默认值。

代码实现

1)修改pojo(数据库表中,自己创建created和updated字段,DateTime类型)

@Data
public class User {
    ...
    // 创建时间,插入一条user数据时候,会自动设置创建时间到updated中
    @TableField(fill = FieldFill.INSERT)
    private Date created;
    
    // 修改时间,执行修改数据时候,会自动设置修改时间到updated中
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updated;
}

2)编写handler

package cn.darzen.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        // 参数1-字段名,参数2-默认值,参数3-固定写
        this.setFieldValByName("created", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 参数1-字段名,参数2-默认值,参数3-固定写
        this.setFieldValByName("updated", new Date(), metaObject);
    }
}

3)测试



@SpringBootTest
@RunWith(SpringRunner.class)
public class Test2 {

    @Autowired
    private UserService userService;

    @Test
    public void save() {
        User user = new User();
        user.setUserName("老王2");
        user.setAge(20);
        userService.save(user);
    }

    @Test
    public void update() {
        User user = new User();
        user.setId(1350766462467121172L);
        user.setUserName("老王2");
        user.setAge(10);
        userService.updateById(user);
    }
}

11. 代码生成器

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

11.1 创建maven工程

创建maven工程:mybatisplus_code

11.2 导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!--父工程给生成后的代码用的-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>


    <groupId>cn.darzen</groupId>
    <artifactId>mybatisplus_code</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

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

        <!--模块引擎-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.30</version>
        </dependency>
        

        <!--下面是生成后的代码需要用到的依赖-->
        <!--web启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--mybatis启动器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

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

    </dependencies>
</project>

11.3 代码生成类

创建test包,复制此类到包下

package test;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
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.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.Scanner;

// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
public class CodeGenerator {

    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");  // 获取当前项目所在目录
        System.out.println(projectPath);
        // 复制自己工程的绝对路径作为代码输出目录
        gc.setOutputDir("D:\\itcast\\ee148\\project148\\mybatisplus_code\\src\\main\\java"); 
        gc.setAuthor("itheima"); // 设置作者

        //设置包
        /* gc.setControllerName("Usercontroller");
        gc.setServiceName("UserService");
        gc.setEntityName("User");
        gc.setServiceImplName("UserServiceImpl");
        gc.setMapperName("UserDao"); */
        gc.setOpen(false);
        // gc.setSwagger2(true); 实体属性 Swagger2 注解

        // 设置全局配置
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mp");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        mpg.setDataSource(dsc); // 设置数据源

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent("com.itheima");  // 包前缀
        pc.setModuleName(scanner("功能模块名")); // 设置功能模块名
        // 设置包配置
        mpg.setPackageInfo(pc);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        // strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        // 公共父类
        // strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
        // 写于父类中的公共字段
        // strategy.setSuperEntityColumns("id");
        strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix("tb_"); // 设置表前缀
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());

        // 执行
        mpg.execute();

    }
}

11.4 执行

右键运行main函数,在控制台输入功能模块名,表名,再按回车即可

在这里插入图片描述

执行完成后刷新项目,发现代码已经生成完毕,每个表都生成对应每一层的代码:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值