01-MybatisPlus的使用

写在前面:本文并不是演示mybatisplus的使用,而是记录一下mybatisplus中使用的一些细节,如果想要详细了解mybatisplus,官网是个不错的选择。这里是官网

1、MybatisPlus快速搭建

在搭建过程中,希望体会以下的几点细节知识。

1.1、引入mybatis-plus相关mavne依赖

这里引入的是mybatis-plus在springboot中的场景启动器。

       <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
  • 项目的全部依赖:
 <!--    mybatis-plus-->
    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
        <!-- mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- 德鲁伊druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!-- lombok,后面会讲,帮我们生成set、get等-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--springboot的测试包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

1.2、数据库

CREATE TABLE `tbl_employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `last_name` varchar(50) DEFAULT NULL,
  `email` varchar(50) DEFAULT NULL,
  `gender` char(1) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


  • 插入几条数据
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Tom','tom@atguigu.com',1,22);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Jerry','jerry@atguigu.com',0,25);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Black','black@atguigu.com',1,30);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('White','white@atguigu.com',0,35);
  • 创表完成
    在这里插入图片描述

1.3、搭建项目结构

1.3.1、select语句让我明白

1.3.1、知识点一

这里直接给出了完整的结构。
在这里插入图片描述

  • 实体类对应代码
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;
    private Integer age;
}
  • EmployeeMapper里面继承了MybatiPlus提供的BaseMapper接口,里面提供了增删改操作。
/**
 * @author liushoushou
 * @create 2021-10-19-22:15
 */
public interface EmployeeMapper  extends BaseMapper<Employee> {

}

== 注意 1、== BaseMapper里面一定填写实体类对象。原因是mybatisplus生成sql语句的方式是:根据BaseMapper泛型所填写的实体类作为数据库表去查找的。

  • 验证注意1:
  • 将EmployeeMapper改为如下,也即去掉了泛型:
/**
 * @author liushoushou
 * @create 2021-10-19-22:15
 */
public interface EmployeeMapper  extends BaseMapper {

}

我们以单元测试方法进行测试。
在这里插入图片描述

  • TestMpApplication中添加测试方法:
@SpringBootTest
public class TestMpApplication {
    // 注入Mapper
    @Autowired
    private EmployeeMapper employeeMapper;
    @Test
    public void  testSelect(){
        Employee employee = employeeMapper.selectById(1);
        System.out.println(employee);
    }
}
  • 执行testSelect()方法,出现如下异常:说明必须在BaseMapper<T>中加上实体类的名字在这里插入图片描述- 将BaseMapper再添加上泛型<Employee>
  • 再次运行上述的testSelect()方法,出现如下异常:实体类名是Employee,它在查找数据库时是employee,而我的表名是tbl_employee,自然会报找不到表了。
    在这里插入图片描述
    将数据库表名改为:Employee
    在这里插入图片描述
  • 再次执行上面的testSelect方法

在这里插入图片描述
在这里插入图片描述

  • 查询到了数据,并且查询语句的表名是employee,数据库是Employee,可以成功。
  • 但是作为数据库命名的方式一般为:“tbl_employee”带下划线,而我们的实体类就都是首字母大写如:“Employee”。要想解决在mybatis根据BaseMapper<实体类>,实体类作为表名的问题。可以使用@TableName注解。
注解描述
TableName添加在实体类上,表明数据库中的表名,在进行crud操作时,会将TableName中的value属性当做表名

语法格式:

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
@TableName("tbl_employee")
public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;
    private Integer age;
}

  • 再次运行testSelect方法,不会报错。
    在这里插入图片描述
    小结 BaseMapper里面一定填写实体类对象。原因是mybatisplus生成sql语句的方式是:根据BaseMapper泛型所填写的实体类作为数据库表去查找的。如果实体类对象和表名不一样,可以通过添加@TableName("数据库中的表名")来解决不一致问题。

1.3.2、insert语句让我明白

  • TestMpApplication类中新增·testInsert()·方法,并运行
@SpringBootTest
public class TestMpApplication {
    // 注入Mapper
    @Autowired
    private EmployeeMapper employeeMapper;
    @Test
    public void  testSelect(){
        Employee employee = (Employee) employeeMapper.selectById(1);
        System.out.println(employee);
    }

    @Test
    public void testInsert(){
        Employee employee=new Employee(null,"瘦瘦","1270295098@qq.com",1,23 );
        employeeMapper.insert(employee);
    }
}

  • 在创建Employee对象时,id属性设置的null,因为数据库中设置了主键自增的操作,按说应该是能插入进行的,但是控制台报错了–数据类型不匹配。
    在这里插入图片描述
  • 分析:这是因为mybatisplus,会自动的把实体类中的名为id的属性当做数据库中的主键,而主键不能为空,所以mybatis就多此一举,自动生成了一个全局唯一的id,并将生成的值赋给当前对象的id(当mybaitsplus发现id属性是数字类型时,会随机生成一个数字,但是这个数字会超过实体类中定义的Integer的范围,所以会报上述的错误,如果把实体类中id改为Long,在将生成的数字赋给当前对象的id时,是不会报错的,但是插入到数据库又会报错,因为数据库设置了自增;同理如果id属性是字符串,就会生成一个字符串赋给当前对象,然后执行数据库插入操作,而此时数据库的id是自增的,自然还会报错。所以目前有两个问题:
    1、如何让mybatisplus知道数据库中哪个字段是主键,而不是让mybatis自以为是的认为实体类中叫id的就是主键;
    2、如何让mybatisplus知道主键是自增的,不需要mybatisplus为我生成一个值当做主键的值)
  • 解决:1、在实体类的主键属性上加如下注解,并设置它的属性为自增。
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
@TableName("tbl_employee")
public class Employee {
    // value对应着数据库中注解的字段名
    // type = IdType.AUTO,告诉mybatis,数据库中注解递增,不用你给我创建全局唯一id
    @TableId(value = "id" ,type = IdType.AUTO)
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;
    private Integer age;
}
  • IdType的另外两个比较常用的属性
    在这里插入图片描述
    它的使用如下:
@TableName("tbl_employee")
public class Employee {
    // value对应着数据库中注解的字段名
    // type = IdType.AUTO,告诉mybatis,数据库中注解递增,不用你给我创建全局唯一id
    @TableId(value = "id" ,type = IdType.ASSIGN_ID)
    private Long id;
    private String lastName;
    private String email;
    private Integer gender;
    private Integer age;
}

value = "id" 告诉mybatisplus,数据库中的主键是id,别瞎猜。
type = IdType.ASSIGN_ID 告诉mybatisplus,数据库中的主键需要你给我生成一个唯一的字符串(这个字符串是纯数字,type = IdType.ASSIGN_UUID 生成的是纯字符串),生成好后赋值给我要插入到数据库对象的id属性上,并且实体类对象的id属性要能够接受到这个值(看上面Employee实体类中id类型已经改为Long了,因为生成的id 超过了Integer范围,会报类型不匹配异常的)。数据库中的字段属性类型要根据上面官方的要求进行更改。

1.3.1、知识点二
  • Employee中的实体类改为如下,主要是将上面测试的id类型为Long,再次的改为Integer·,TableId中的type = IdType.AUTO
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
@TableName("tbl_employee")
public class Employee {
    // value对应着数据库中注解的字段名
    @TableId(value = "id" ,type = IdType.AUTO)
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;
    private Integer age;
}

在这里插入图片描述

  • TestMpApplication中,更改上面的testInsert方法,将Employee对象的部分字段改为空,查看生成的sql语句。
    在这里插入图片描述

在这里插入图片描述
可以看到插入对象时,只会插入非空的字段,对于更新操作,也是只更新非空的属性,sql语句也是只生成非null的字段,像不像mybatis中的动态sql呢

  • 更改实体类对象,添加一个任意字段:
    在这里插入图片描述
  • 当进行插入操作时,因为该属性在数据库中并不存在,所以根据上面的结论:如果该字段为null的话,在生成的sql语句中就不会包含该字段,如果该字段不为null的话,在生产的sql语句就会有该字段,而数据库中没有就会报错。下面演示错误情况,修改刚才的testInsert()方法。
  • 在这里插入图片描述
  • 结果
    在这里插入图片描述
  • 那么如何让实体类属性中的非空字段不生成在sql语句当中呢?使用注解@TableField(exist = false)
  • zai在这里插入图片描述
  • 查看运行结果
    在这里插入图片描述
1.3.3、知识点三
  • 更改方法
    在这里插入图片描述
  • 查看生成的sql语句
    在这里插入图片描述
  • 可以看到sql语句:
    INSERT INTO tbl_employee ( last_name, email, gender, age ) VALUES ( ?, ?, ?, ? )实体类是lastName,mybatis在执行插入时变成了last_name,说明mybatisplus默认开启了自动驼峰命名规则(camel case)映射去官网
    在这里插入图片描述
  • 想要关闭的话,直接在yml中配置。(默认是开启的)
  • 在这里插入图片描述
    再次运行上面的插入操作,出现异常。
    在这里插入图片描述
1.3.4、几个方法的说明

更改项目结构,上面我们的项目并没有service层,而我们在开发的时候三层结构还是要遵守的。下面更改项目结构。主要是添加service包和serviceimp包。
在这里插入图片描述

  • service包中的EmployeeService中的类声明如下:

在这里插入图片描述

  • serviceimp包下的EmployeeServiceImpl类如下
    在这里插入图片描述
  • 完成这样,EmployeeServiceImpl就有大量的操作数据库的方法
  • 测试,新建测试类
    在这里插入图片描述
    在这里插入图片描述
    注意:在直接使用mapper接口完成插入操作时,直接是insert、而使用service完成插入是save方法。
    在这里插入图片描述
  • 运行结果:
    在这里插入图片描述
  • 注意:它的命名可以学习,且看到它还给我门添加了事务。(贴心的小棉袄)
    在这里插入图片描述

saveOrUpdate说明

public boolean saveOrUpdate(T entity) {
        if (null == entity) {
            return false;
        } else {
            Class<?> cls = entity.getClass();
            TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
            Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]);
            String keyProperty = tableInfo.getKeyProperty();
            Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!", new Object[0]);
            Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty());
            return !StringUtils.checkValNull(idVal) && !Objects.isNull(this.getById((Serializable)idVal)) ? this.updateById(entity) : this.save(entity);
        }
    }

在这里插入图片描述

  • 执行如下的方法
    在这里插入图片描述
  • 执行结果,此时数据库已经存在id为2的数据了。
    在这里插入图片描述
  • 改id数据库中不存在的,查看情况,我把employee对象的id改为了5,查看
    在这里插入图片描述

2、分页操作

一、自定义使用

第一步:添加分页插件官网

更新一下依赖的版本,我上面的版本不支持新的插件配置。以前的配置可以看官网,这里使用新的插件配置。

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3.4</version>
        </dependency>

在项目下创建一个配置类,先创建一个配置的包。这里直接在主启动类里面配置了,也可以加入到容器中。
在这里插入图片描述

第二步:使用分页

  • 在测试中使用分页
    在这里插入图片描述

  • 测试运行结果:
    在这里插入图片描述

  • 可以看到,上面执行了两条sql语句,第一条得到数据库中的总数量,然后给IPage类中的total属性,根据总数量算出来分页数给了
    ·pages·属性。然后再执行依据分页语句,查询到当前页的数据。给了IPage类中的records属性。

二、XML使用

比如:多表联合查询到的数据,我们就需要自定义sql语句了,那么我们该怎样完成分页操作呢。

  • 在mapper中编写接口
/**
 * @author liushoushou
 * @create 2021-10-19-22:15
 */
public interface EmployeeMapper  extends BaseMapper<Employee> {

    /**
     * 查询gender=1的信息,并使用分页
     *  @param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位(你可以继承Page实现自己的分页对象)
     *  @param  gender 参数
     *  return 分页对象
     */
    IPage<Employee> selectPageVo(IPage<Employee> page ,String gender);
}
  • EmployeeMapper.xml等同于编写一个普通 list 查询,mybatis-plus 自动替你分页,EmployeeMapper.xml声明在如下的结构中:
    在这里插入图片描述
<mapper namespace="com.shoushou.mapper.EmployeeMapper">

    <select id="selectPageVo" resultType="com.shoushou.pojo.Employee">
        select * from tbl_employee where gender=#{gender}
    </select>

</mapper>
  • EmployeeServiceImpl调用分页方法
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService  {
    @Autowired
    private EmployeeMapper employeeMapper;

    public IPage<Employee> selectEmployeePage(IPage<Employee>page,String gender){
        // 要点!! 分页返回的对象与传入的对象是同一个
        IPage<Employee> iPage = employeeMapper.selectPageVo(page, gender);
        return  iPage;
    }
}

注意:在该操作中,我并没有指明mapper文件的位置,这是因为mybatisplus,默认给我们指明了路径。
我们知道,一般springboot会自动加载xxxxAutoConfiguration自动配置类,那我们就找到MybatisPlusAutoConfiguration:
在这里插入图片描述

  • 该类中,@EnableConfigurationProperties({MybatisPlusProperties.class}),一看就是配置类,点进去查看:
    -在这里插入图片描述
  • 这就是为啥不用在yml或者properties中配置的原因。可以在yml或者properties中改变默认扫描的路径。
    在这里插入图片描述

三、条件构造器

在这里插入图片描述
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件,QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
在这里插入图片描述
AbstractWrapper比较重要,里面的方法需要
重点学习. 该抽象类提供的重要方法如下:请添加图片描述请添加图片描述

  • 示例:
 @Test
    public void testQueryWrapper(){
        QueryWrapper<Employee> queryWrapper=new QueryWrapper();
        // 注意select想要的字段,字段名是数据库中的名字
        // 该语句的意思是,查询的字段为last_name,age 并且gender=1
        // 方式一:这种方法属于编码,在代码中写死了
        queryWrapper.select("last_name", "age")
                // inSql是子查询
                .inSql("id","select 1 from dual");
       //方式二:使用lambda方式
        LambdaQueryWrapper<Employee> lambda = queryWrapper.lambda();
        // select中是函数式接口 Function<T, R>
        lambda.select(Employee::getLastName,Employee::getAge)
                .eq(Employee::getId,"2");
        List<Employee> employees = employeeService.list(queryWrapper);
        employees.forEach(System.out::println);

    }

    @Test
    public void testUpdateWrapper(){
        UpdateWrapper<Employee> updateWrapper=new UpdateWrapper<>();
        updateWrapper.set("last_name","张x").set("age",18)
                .eq("id",3);
        // 同理lambda
        LambdaUpdateWrapper<Employee> lambda = updateWrapper.lambda();
        lambda.set(Employee::getLastName,"zhangx");
        boolean update = employeeService.update(updateWrapper);
        System.out.println(update);
    }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值