- 1.MyBatis介绍
- 1.1.MyBatisPlus概述
- 1.2.MyBatisPlus特性
- 1.3.MyBatisPlus架构
- 2.快速开始
- 2.1.创建数据库以及表
- 2.2.创建工程
- 2.2.1.在IDEA中创建一个Maven工程
- 2.2.2.在pom.xml中导入相关依赖
- 2.3.Mybatis+MP
- 2.3.1.创建子Module
- 2.3.2.Mybatis实现查询User
- 2.3.3.Mybatis+MP实现查询User
- 2.4.Spring + Mybatis + MP
- 2.4.1.创建子Module
- 2.4.2.实现查询User
- 2.5.SpringBoot + Mybatis + MP
- 2.5.1.创建工程
- 2.5.2.编写相关的配置文件
- 3.通用CRUD
- 3.1.插入操作——insert
- 3.1.1.方法定义
- 3.1.2.编写测试方法进行测试
- 3.1.4.@TableField注解
- 3.2.更新操作
- 3.2.1.根据id更新——updateById
- 3.2.2.根据条件更新——update
- 3.3.删除操作
- 3.3.1.根据id删除——deleteById
- 3.3.2.根据条件删除——deleteByMap
- 3.3.3.根据条件删除——delete
- 3.3.3.批量删除——deleteBatchIds
- 3.4.查询操作
- 3.4.1.根据id查询——selectById
- 3.4.2.批量查询——selectBatchIds
- 3.4.3.查询单条数据——selectOne
- 3.4.4.查询数据条数——selectCount
- 3.4.5.查询数据列表——selectList
- 3.4.6.分页查询数据——selectPage
- 4.配置
- 4.1.基本配置
- 4.1.1.configLocation
- 4.1.2.mapperLocations
- 4.1.3.typeAliasesPackage
- 4.2.进阶配置
- 4.2.1.mapUnderscoreToCamelCase
- 4.2.2.cacheEnabled
- 4.3.DB 策略配置
- 4.3.1.idType
- 4.3.2.tablePrefix
- 5.条件构造器
- 5.1.allEq
- 5.2.基本比较操作
- 5.3.模糊查询
- 5.4.排序
- 5.5.逻辑查询
- 5.6.select
- 6.ActiveRecord
- 6.1.ActiveRecord介绍
- 6.2.AR快速入门
- 7.插件
- 7.1.MyBatis的插件机制
- 7.2.SQL执行分析插件
- 7.2.1.配置SQL分析插件
- 7.2.2.编写测试代码
- 7.3.SQL性能分析插件
- 7.3.1.配置SQL性能分析插件
- 7.3.2.编写测试代码
- 7.4.乐观锁插件
- 7.4.1.乐观锁介绍
- 7.4.2.插件配置方式
- 7.4.3.注解实体字段
- 7.4.4.编写测试代码
- 7.4.5.特别说明
- 8.Sql 注入器
- 8.1.编写MyBaseMapper
- 8.2.编写MySqlInjector
- 8.3.编写FindAll
- 8.4.注册到Spring容器中
- 8.5.编写测试方法
- 9.自动填充功能
- 9.1.添加@TableField注解
- 9.2.编写MyMetaObjectHandler
- 9.3.编写测试用例
- 10.逻辑删除
- 10.1.修改表结构
- 10.2.在application.properties中进行配置
- 10.3.编写测试方法
- 11.通用枚举
- 11.1.修改表结构
- 11.2.定义枚举
- 11.3.在application.properties中进行配置
- 11.4.修改实体类User
- 11.5.编写测试方法
- 12.代码生成器
- 12.1.创建工程
- 12.2.在pom.xml中导入相关依赖
- 12.3.生成器代码
- 13.MybatisX——快速开发插件
- 13.1.安装方法
- 13.2.功能
本文章笔记整理来自黑马视频https://www.bilibili.com/video/BV1rE41197jR,相关资料可以在视频评论取领取。
1.MyBatis介绍 1.1.MyBatisPlus概述(1)MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 (2)官方地址:https://mybatis.plus/ 或者https://mp.baomidou.com/。 (3)文档地址:https://mybatis.plus/guide/或者https://mp.baomidou.com/guide/。 (4)源码地址:https://github.com/baomidou/mybatis-plus。 (5)Mybatis-Plus是由baomidou(苞米豆)组织开发并且开源的,码云地址为:https://gitee.com/organizations/baomidou
1.2.MyBatisPlus特性 无侵入只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑损耗小启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作强大的 CRUD 操作内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求支持 Lambda 形式调用通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库支持主键自动生成支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题支持 XML 热加载Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动支持 ActiveRecord 模式支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作支持自定义全局通用操作支持全局通用方法注入( Write once, use anywhere )支持关键词自动转义支持数据库关键词(order、key…)自动转义,还可自定义关键词内置代码生成器采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用内置分页插件基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List查询内置性能分析插件可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询内置全局拦截插件提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作内置 Sql 注入剥离器支持 Sql 注入剥离,有效预防 Sql 注入攻击 1.3.MyBatisPlus架构对于Mybatis整合MP有常常有三种用法,分别是Mybatis+MP、Spring+Mybatis+MP、Spring Boot+Mybatis+MP。
2.1.创建数据库以及表(1)创建名为mp的数据库,且字符集选择utf8。 (2)在mp数据库中创建一张名为tb_user的表,并且插入一些测试数据,对应的SQL语句如下:
-- 创建测试表
CREATE TABLE `tb_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_name` varchar(20) NOT NULL COMMENT '用户名',
`password` varchar(20) NOT NULL COMMENT '密码',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 插入测试数据
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES
('1', 'zhangsan', '123456', '张三', '18', 'test1@itcast.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES
('2', 'lisi', '123456', '李四', '20', 'test2@itcast.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES
('3', 'wangwu', '123456', '王五', '28', 'test3@itcast.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES
('4', 'zhaoliu', '123456', '赵六', '21', 'test4@itcast.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES
('5', 'sunqi', '123456', '孙七', '24', 'test5@itcast.cn');
4.0.0
cn.itcast.mp
itcast-mybatis-plus
1.0-SNAPSHOT
com.baomidou
mybatis-plus
3.1.1
mysql
mysql-connector-java
5.1.47
com.alibaba
druid
1.0.11
org.projectlombok
lombok
true
1.18.4
junit
junit
4.12
org.slf4j
slf4j-log4j12
1.6.4
org.apache.maven.plugins
maven-compiler-plugin
1.8
1.8
2.3.Mybatis+MP
2.3.1.创建子Module
在resources目录下创建日志配置文件log4j.properties
log4j.rootLogger=DEBUG,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n
2.3.2.Mybatis实现查询User
(1)创建MyBatis全局配置文件mybatis-config.xml
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
(2)创建User实体类以及UserMapper接口、UserMapper.xml文件
package cn.itcast.mp.simple.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private String email;
}
package cn.itcast.mp.simple.mapper;
import cn.itcast.mp.simple.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
public interface UserMapper{
List findAll();
}
(3)编写TestMybatis测试用例
package cn.itcast.mp.simple;
import cn.itcast.mp.simple.mapper.UserMapper;
import cn.itcast.mp.simple.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class TestMybatis {
@Test
public void testFindAll() throws Exception{
String config = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(config);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//测试查询
List users = userMapper.findAll();
for (User user : users) {
System.out.println(user);
}
}
}
结果如下:
(1)将UserMapper继承BaseMapper,这样将拥有BaseMapper中的所有方法
package cn.itcast.mp.simple.mapper;
import cn.itcast.mp.simple.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
public interface UserMapper extends BaseMapper {
List findAll();
}
(2)在User类上添加注解@TableName(“tb_user”),指定该实体类所对应的数据库表名(如果不添加该注解,则会出现Table ‘mp.user’ dosen’t exist的错误提示)
(3)使用MP中的MybatisSqlSessionFactoryBuilder进行构建
package cn.itcast.mp.simple;
import cn.itcast.mp.simple.mapper.UserMapper;
import cn.itcast.mp.simple.pojo.User;
import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class TestMybatisPlus {
@Test
public void testFindAll() throws Exception{
String config = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(config);
//这里使用的是MP中的MybatisSqlSessionFactoryBuilder
SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//测试查询
// List users = userMapper.findAll();
List users = userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
}
结果如下:
引入了Spring框架后,数据源、构建等工作就交给了Spring管理。
2.4.1.创建子Module与上面一样,创建一个名为itcast-mybatis-plus-spring的子Module,并在pom.xml中导入Spring的相关依赖
itcast-mybatis-plus
cn.itcast.mp
1.0-SNAPSHOT
4.0.0
itcast-mybatis-plus-spring
5.1.6.RELEASE
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-jdbc
${spring.version}
org.springframework
spring-test
${spring.version}
2.4.2.实现查询User
(1)编写数据库配置文件jdbc.properties以及日志配置文件log4j.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false
jdbc.username=root
jdbc.password=123456
log4j.rootLogger=DEBUG,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n
(2)编写Spring配置文件applicationContext.xml以及MyBatis配置文件mybatis-config.xml
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
(3)创建User实体类以及UserMapper接口(与上面的基本一样,可以直接复制) (4)编写测试用例
package cn.itcast.mp.simple;
import cn.itcast.mp.simple.mapper.UserMapper;
import cn.itcast.mp.simple.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestMybatisSpring {
@Autowired
private UserMapper userMapper;
@Test
public void testSelectList(){
//不带条件查询用户,即查询所有使用户
List users = this.userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
}
结果如下:
使用SpringBoot将进一步的简化MP的整合,需要注意的是,由于使用SpringBoot需要继承parent,所以需要重新创建工程,并不是创建子Module。
2.5.1.创建工程(1)创建一个名为itcast-mp-springboot的工程 (2)在pom.xml中导入相关依赖
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.4.RELEASE
cn.itcast.mp
itcast-mp-springboot
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-logging
org.springframework.boot
spring-boot-starter-test
test
org.projectlombok
lombok
true
com.baomidou
mybatis-plus-boot-starter
3.1.1
mysql
mysql-connector-java
5.1.47
org.slf4j
slf4j-log4j12
org.springframework.boot
spring-boot-maven-plugin
2.5.2.编写相关的配置文件
(1)日志配置文件log4j.properties
log4j.rootLogger=DEBUG,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n
(2)SpringBoot全局配置文件application.properties
spring.application.name = itcast-mp-springboot
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
(3)创建User实体类以及UserMapper接口(与上面的基本一样,可以直接复制) (4)编写SpringBoot启动类
package cn.itcast.mp;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("cn.itcast.mp.mapper") //设置mapper接口的扫描包
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
(4)编写测试用例
package cn.itcast.mp;
import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.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.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class TestMybatisSpringBoot {
@Autowired
private UserMapper userMapper;
@Test
public void testSelectList(){
List users = this.userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
}
结果如下:
通过前面的学习,我们已经了解到通过继承BaseMapper就可以获取到下面各种各样的单表操作方法,接下来我们将详细讲解这些操作。
/**
* 插入一条记录
*
* @param entity 实体对象
*/
int insert(T entity);
3.1.2.编写测试方法进行测试
package cn.itcast.mp;
import cn.itcast.mp.mapper.UserMapper;
import cn.itcast.mp.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 TestUserMapper {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert() {
User user = new User();
user.setUserName("xiaowang");
user.setPassword("123456");
user.setName("小王");
user.setAge(21);
user.setEmail("xiaowang@163.com");
//result:数据库受影响的行数
int result = this.userMapper.insert(user);
System.out.println("result => " + result);
//获取自增长后的id值, 自增长后的id值会回填到user对象中
System.out.println("id => " + user.getId());
}
}
测试结果如下:
可以看到,数据已经写入到了数据库,但是,id的值不正确,我们期望的是数据库自增长,而实际是MP自动生成的id值写入到了数据库之中。 所以应该设置id的生成策略,MP支持的id策略如下:
/*
* Copyright (c) 2011-2020, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.baomidou.mybatisplus.annotation;
import lombok.Getter;
/**
* 生成ID类型枚举类
*
* @author hubin
* @since 2015-11-10
*/
@Getter
public enum IdType {
/**
* 数据库ID自增
*/
AUTO(0),
/**
* 该类型为未设置主键类型
*/
NONE(1),
/**
* 用户输入ID
*
该类型可以通过自己注册自动填充插件进行填充
*/
INPUT(2),
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
* 全局唯一ID (idWorker)
*/
ID_WORKER(3),
/**
* 全局唯一ID (UUID)
*/
UUID(4),
/**
* 字符串全局唯一ID (idWorker 的字符串表示)
*/
ID_WORKER_STR(5);
private final int key;
IdType(int key) {
this.key = key;
}
}
所以应该在User类中指定id的类型: 此外,还需要在数据库中修改tb_user表中id字段的下一个自增值。
最后,再次进行测试
在MP中通过@TableField注解可以指定字段的一些属性,常常解决的问题有以下两个: (1)对象中的属性名和字段名不一致的问题(非驼峰命名); (2)对象中的属性字段在表中不存在的问题;
package cn.itcast.mp.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
//@TableName("tb_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String userName;
@TableField(select = false) //查询时不返回该字段的值
private String password;
private String name;
private Integer age;
@TableField(value = "email") //指定数据表中字段名
private String mail;
@TableField(exist = false) //在数据库表中是不存在的
private String address;
}
3.2.更新操作
在MP中,更新操作有两种,一种是根据id更新,另一种是根据条件更新。
3.2.1.根据id更新——updateById(1)方法定义
/**
* 根据 ID 修改
*
* @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);
(2)编写测试代码
@Test
public void testUpdateById(){
User user = new User();
user.setId(1L);
user.setPassword("111111");
user.setEmail("111@163.com");
//将id为1的用户的密码改为111111、邮箱改为111@163.com
int result = this.userMapper.updateById(user);
System.out.println("result => " + result);
}
(1)方法定义
/**
* 根据 whereEntity 条件,更新记录
*
* @param entity 实体对象 (set 条件值,可以为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper updateWrapper);
(2)编写测试代码 ① 通过QueryWrapper进行更新:
@Test
public void testUpdate1(){
User user = new User();
user.setPassword("888888");
user.setAge(29);
QueryWrapper wrapper = new QueryWrapper();
//匹配user_name = zhangsan 的用户数据
wrapper.eq("user_name", "zhangsan");
/*
上面的操作相当于SQL语句:
update tb_user set password = '888888' , age = 29 where user_name = 'zhangsan'
*/
int result = this.userMapper.update(user,wrapper);
System.out.println("result => " + result);
}
② 通过UpdateWrapper进行更新:
@Test
public void testUpdate2() {
UpdateWrapper wrapper = new UpdateWrapper();
wrapper.set("age", 29).set("password", "888888") //更新的字段
.eq("user_name", "zhangsan"); //更新的条件
int result = this.userMapper.update(null, wrapper);
System.out.println("result => " + result);
}
(1)方法定义
/**
* 根据 ID 删除
*
* @param id 主键ID
*/
int deleteById(Serializable id);
(2)编写测试代码
@Test
public void testDeleteById(){
// 根据id删除数据
int result = this.userMapper.deleteById(6L);
System.out.println("result => " + result);
}
(1)方法定义
/**
* 根据 columnMap 条件,删除记录
*
* @param columnMap 表字段 map 对象
*/
int deleteByMap(@Param(Constants.COLUMN_MAP) Map columnMap);
(2)编写测试代码
@Test
public void testDeleteByMap(){
Map map = new HashMap();
map.put("user_name", "xiaowang");
map.put("password", "123456");
//根据map删除数据,多条件之间是and关系
int result = this.userMapper.deleteByMap(map);
System.out.println("result => " + result);
}
(1)方法定义
/**
* 根据 entity 条件,删除记录
*
* @param wrapper 实体对象封装操作类(可以为 null)
*/
int delete(@Param(Constants.WRAPPER) Wrapper wrapper);
(2)编写测试代码 ① 方式一
@Test
public void testDelete1(){
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq("user_name", "caocao1")
.eq("password", "123456"); //删除的条件
int result = this.userMapper.delete(wrapper);
System.out.println("result => " + result);
}
② 方式二(推荐使用)
@Test
public void testDelete2(){
User user = new User();
user.setPassword("123456");
user.setUserName("xiaowang");
QueryWrapper wrapper = new QueryWrapper(user);
// 根据包装条件做删除
int result = this.userMapper.delete(wrapper);
System.out.println("result => " + result);
}
(1)方法定义
/**
* 删除(根据ID 批量删除)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
int deleteBatchIds(@Param(Constants.COLLECTION) Collection idList);
(2)编写测试代码
@Test
public void testDeleteBatchIds(){
// 根据id批量删除数据
int result = this.userMapper.deleteBatchIds(Arrays.asList(8L, 9L));
System.out.println("result => " + result);
}
MP提供了多种查询操作,包括根据id查询、批量查询、查询单条数据、查询列表、分页查询等操作。
3.4.1.根据id查询——selectById(1)方法定义
/**
* 根据 ID 查询
*
* @param id 主键ID
*/
T selectById(Serializable id);
(2)编写测试代码
@Test
public void testSelectById() {
//根据id查询数据
User user = this.userMapper.selectById(2L);
System.out.println("result = " + user);
}
(1)方法定义
/**
* 查询(根据ID 批量查询)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
List selectBatchIds(@Param(Constants.COLLECTION) Collection idList);
(2)编写测试代码
@Test
public void testSelectBatchIds(){
// 根据id批量查询数据
List users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 4L, 100L));
for (User user : users) {
System.out.println(user);
}
}
(1)方法定义
/**
* 根据 entity 条件,查询一条记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
T selectOne(@Param(Constants.WRAPPER) Wrapper queryWrapper);
(2)编写测试代码
@Test
public void testSelectOne(){
QueryWrapper wrapper = new QueryWrapper();
//查询条件
wrapper.eq("password", "111111");
User user = this.userMapper.selectOne(wrapper);
System.out.println(user);
}
注:当查询的数据超过一条时(例如有4条数据),会抛出如下异常:
org.mybatis.spring.MyBatisSystemException:
nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4
3.4.4.查询数据条数——selectCount
(1)方法定义
/**
* 根据 Wrapper 条件,查询总记录数
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Integer selectCount(@Param(Constants.WRAPPER) Wrapper queryWrapper);
(2)编写测试代码
@Test
public void testSelectCount(){
QueryWrapper wrapper = new QueryWrapper();
wrapper.gt("age", 24); // 条件:年龄大于20岁的用户
//根据条件查询数据条数
Integer count = this.userMapper.selectCount(wrapper);
System.out.println("count => " + count);
}
(1)方法定义
/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper);
(2)编写测试代码
@Test
public void testSelectList(){
QueryWrapper wrapper = new QueryWrapper();
//设置查询条件
wrapper.like("email", "itcast");
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
(1)方法定义
/**
* 根据 entity 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
IPage selectPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper);
/*
* Copyright (c) 2011-2020, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.baomidou.mybatisplus.extension.plugins.pagination;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import java.util.Collections;
import java.util.List;
/**
* 简单分页模型
*
* @author hubin
* @since 2018-06-09
*/
public class Page implements IPage {
private static final long serialVersionUID = 8545996863226528798L;
/**
* 查询数据列表
*/
private List records = Collections.emptyList();
/**
* 总数
*/
private long total = 0;
/**
* 每页显示条数,默认 10
*/
private long size = 10;
/**
* 当前页
*/
private long current = 1;
/**
* SQL 排序 ASC 数组
*/
private String[] ascs;
/**
* SQL 排序 DESC 数组
*/
private String[] descs;
/**
* 自动优化 COUNT SQL
*/
private boolean optimizeCountSql = true;
/**
* 是否进行 count 查询
*/
private boolean isSearchCount = true;
public Page() {
// to do nothing
}
/**
* 分页构造函数
*
* @param current 当前页
* @param size 每页显示条数
*/
public Page(long current, long size) {
this(current, size, 0);
}
public Page(long current, long size, long total) {
this(current, size, total, true);
}
public Page(long current, long size, boolean isSearchCount) {
this(current, size, 0, isSearchCount);
}
public Page(long current, long size, long total, boolean isSearchCount) {
if (current > 1) {
this.current = current;
}
this.size = size;
this.total = total;
this.isSearchCount = isSearchCount;
}
/**
* 是否存在上一页
*
* @return true / false
*/
public boolean hasPrevious() {
return this.current > 1;
}
/**
* 是否存在下一页
*
* @return true / false
*/
public boolean hasNext() {
return this.current
(3)编写测试代码
@Test
public void testSelectPage(){
//查询第三页,查询2条数据
Page page = new Page(3,2);
QueryWrapper wrapper = new QueryWrapper();
//设置查询条件
wrapper.like("email", "itcast");
IPage iPage = this.userMapper.selectPage(page, wrapper);
System.out.println("数据总条数: " + iPage.getTotal());
System.out.println("数据总页数: " + iPage.getPages());
System.out.println("当前页数: " + iPage.getCurrent());
//当前页数的所有记录
List records = iPage.getRecords();
for (User record : records) {
System.out.println(record);
}
}
数据库中的数据如下: 查询结果如下:
在MP中有大量的配置,其中有一部分是Mybatis原生的配置,另一部分是MP的配置,详情请见官方文档https://mp.baomidou.com/config/。
4.1.基本配置 4.1.1.configLocationconfigLocation即MyBatis 全局配置文件位置,如果有单独的 MyBatis 配置,请将其路径配置到 configLocation 中。 MyBatis Configuration 的具体内容请参考MyBatis 官方文档。 (1)SpringBoot
# 指定MyBatis全局的配置文件
mybatis-plus.config-location = classpath:mybatis-config.xml
(2)SpringMVC
4.1.2.mapperLocations
mapperLocations,即MyBatis Mapper 所对应的 XML 文件位置,如果在 Mapper 中有自定义方法(XML 中有自定义实现),需要进行该配置,告诉 Mapper 所对应的 XML 文件位置。 (1)SpringBoot
# 指定Mapper.xml文件的路径
mybatis-plus.mapper-locations = classpath*:mybatis/*.xml
(2)SpringMVC
4.1.3.typeAliasesPackage
typeAliasesPackage,即MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML 文件中可以直接使用类名,而不用使用全限定的类名(即 XML 中调用的时候不用包含包名)。 (1)SpringBoot
mybatis-plus.type-aliases-package = cn.itcast.mp.pojo
(2)SpringMVC
4.2.进阶配置
本部分(Configuration)的配置大都为 MyBatis 原生支持的配置,这意味着您可以通过MyBatis XML 配置文件的形式进行配置。
4.2.1.mapUnderscoreToCamelCasemapUnderscoreToCamelCase,即是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射。类型为boolean,默认值为 true。 注意:此属性在 MyBatis 中原默认值为 false,在 MyBatis-Plus 中,此属性也将用于生成最终的 SQL 的 select body,如果数据库命名符合规则,则无需使用 @TableField 注解指定数据库字段名。 (1)SpringBoot
#开启自动驼峰映射,该参数不能和mybatis-plus.config-location同时存在
mybatis-plus.configuration.map-underscore-to-camel-case=true
(2)MyBatis
4.2.2.cacheEnabled
cacheEnabled,即全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,类型为boolean,默认值为 true。 (1)SpringBoot
mybatis-plus.configuration.cache-enabled=false
(2)MyBatis
4.3.DB 策略配置
4.3.1.idType
类型com.baomidou.mybatisplus.annotation.IdType默认值ID_WORKERidType,即全局默认主键类型,设置后,即可省略实体对象中的@TableId(type =IdType.AUTO)配置。(1)SpringBoot
# 全局的id自增策略
mybatis-plus.global-config.db-config.id-type=auto
(2)SpringMVC
4.3.2.tablePrefix
tablePrefix,即表名前缀,全局配置后可省略@TableName()配置。 (1)SpringBoot
# 全局的表名的前缀
mybatis-plus.global-config.db-config.table-prefix=tb_
(2)SpringMVC
5.条件构造器
在MP中,Wrapper接口的实现类关系如下: 可以看到,AbstractWrapper和AbstractChainWrapper是重点实现,接下来重点学习AbstractWrapper以及其子类。条件构造器的官网文档地址为:https://mp.baomidou.com/guide/wrapper.html。 说明:QueryWrapper(LambdaQueryWrapper) 和UpdateWrapper(LambdaUpdateWrapper) 的父类用于生成sql的where条件,entity属性也用于生成sql的where条件。但entity生成的where条件与使用各个api生成的where条件没有任何关联行为
(1)说明
allEq(Map params)
allEq(Map params, boolean null2IsNull)
allEq(boolean condition, Map params, boolean null2IsNull)
allEq(BiPredicate filter, Map params)
allEq(BiPredicate filter, Map params, boolean null2IsNull)
allEq(boolean condition, BiPredicate filter, Map params, boolean null2IsNull)
部分参数说明: params: key 为数据库字段名,value为字段值。 null2IsNull: 为 true时,则在map的value为null时调用isNull方法;为false时,则忽略 value为null时的条件。
例1: allEq({id:1,name:"老王",age:null}) ---> id = 1 and name = '老王' and age is null
例2: allEq({id:1,name:"老王",age:null}, false) ---> id = 1 and name = '老王'
filter: 过滤函数,是否允许字段传入比对条件中 params (2)编写测试用例
@Test
public void testAlleq(){
Map params = new HashMap();
params.put("name", "李四");
params.put("age", "20");
params.put("password", null);
QueryWrapper wrapper = new QueryWrapper();
//SELECT id,user_name,password,name,age,email FROM tb_user WHERE password IS NULL AND name = ? AND age = ?
//wrapper.allEq(params);
//SELECT id,user_name,password,name,age,email FROM tb_user WHERE name = ? AND age = ?
//wrapper.allEq(params,false);
//只有age字段比对成功
//SELECT id,user_name,password,name,age,email FROM tb_user WHERE age = ?
//wrapper.allEq((k,v)->(k.equals("age") || k.equals("id")),params);
//age字段和name字段比对成功
//Preparing: SELECT id,user_name,password,name,age,email FROM tb_user WHERE name = ? AND age = ?
wrapper.allEq((k, v) -> (k.equals("age") || k.equals("id") || k.equals("name")) , params);
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
5.2.基本比较操作
(1)说明
eq等于 =ne不等于 gt大于 >ge大于等于 >=lt小于 name like ‘%王%’notLikeNOT LIKE ‘%值%’,例: notLike(“name”, “王”) —> name not like ‘%王%’likeLeftLIKE ‘%值’,例: likeLeft(“name”, “王”) —> name like ‘%王’likeRightLIKE ‘值%’,例: likeRight(“name”, “王”) —> name like ‘王%’(2)编写测试用例
@Test
public void testLike(){
QueryWrapper wrapper = new QueryWrapper();
// SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name LIKE ?
// 参数:%五(String)
wrapper.likeLeft("name", "五");
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
(1)说明
orderBy排序:ORDER BY 字段, …orderByAscORDER BY 字段, … ASCorderByDescORDER BY 字段, … ASC(2)编写测试用例@Test
public void testOrderByAgeDesc(){
QueryWrapper wrapper = new QueryWrapper();
//按照年龄倒序排序
wrapper.orderByDesc("age");
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
(1)说明
or拼接 OR,主动调用 or 表示紧接着下一个方法不是用 and 连接!(不调用 or 则默认为使用 and 连接)andAND 嵌套,例: and(i -> i.eq(“name”, “李白”).ne(“status”, “活着”)) —> and (name = ‘李白’ and status ‘活着’)(2)编写测试用例@Test
public void testOr(){
QueryWrapper wrapper = new QueryWrapper();
// SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name = ? OR age = ?
wrapper.eq("name", "王五").or().eq("age", 21);
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
(1)说明 在MP查询中,默认查询所有的字段,如果有需要也可以通过select方法进行指定字段。 (2)编写测试用例
@Test
public void testSelect(){
QueryWrapper wrapper = new QueryWrapper();
//SELECT id,name,age FROM tb_user WHERE name = ? OR age = ?
wrapper.eq("name", "王五")
.or()
.eq("age", 21)
.select("id","name","age"); //指定查询的字段
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
(1)ActiveRecord属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而且简洁易懂。 (2)ActiveRecord的主要思想是: ① 每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;通常表的每个字段在类中都有相应的Field; ② ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的CURD; ③ ActiveRecord是一种领域模型(Domain Model),封装了部分业务逻辑; (3)ActiveRecord(简称AR)一直广受动态语言( PHP 、 Ruby 等)的喜爱,而 Java 作为准静态语言,对于ActiveRecord 往往只能感叹其优雅,所以我们开发团队也在 AR 道路上进行了一定的探索。
6.2.AR快速入门(1)在MP中,开启AR非常简单,只需要将实体对象继承Model即可。
package cn.itcast.mp.pojo;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
//@TableName("tb_user")
public class User extends Model{
//@TableId(type = IdType.AUTO)
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private String email;
}
(2)编写测试代码
@Test
public void testSelectById(){
User user = new User();
user.setId(2L);
//不需要显示地注入UserMapper
User user1 = user.selectById();
System.out.println(user1);
}
有关Mybatis中的插件机制方面的知识,作者已经在MyBatis3——入门介绍这篇文章的第10节进行了总结,有需要的读者可以前往查看你,所以此处不再赘述。
7.2.SQL执行分析插件MP提供了对SQL执行的分析插件,可用作阻断全表更新、删除的操作(注意:该插件仅适用于开发环境,不适用于生产环境)
7.2.1.配置SQL分析插件下面是在SpringBoot项目的配置类中进行的配置。
@Bean //SQL分析插件
public SqlExplainInterceptor sqlExplainInterceptor(){
SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor();
List list = new ArrayList();
list.add(new BlockAttackSqlParser()); //全表更新、删除的阻断器
sqlExplainInterceptor.setSqlParserList(list);
return sqlExplainInterceptor;
}
7.2.2.编写测试代码
@Test
public void testUpdateAll(){
User user = new User();
user.setAge(31); // 更新的数据
//全表更新,但是这对SQL执行分析插件来说是不可取的
boolean result = user.update(null);
System.out.println("result => " + result);
}
由于SQL执行分析插件的配置,上述测试代码中的全表更新操作是会被阻断的:
org.apache.ibatis.exceptions.PersistenceException:
### Error updating database. Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Prohibition of table update operation
### Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Prohibition of table update operation
7.3.SQL性能分析插件
SQL性能分析拦截器,用于输出每条 SQL 语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常(该插件只用于开发环境,不建议生产环境使用)。
7.3.1.配置SQL性能分析插件下面是在MyBatis的全局配置文件mybatis-config.xml中进行的配置。
7.3.2.编写测试代码
@Test
public void testSelectById(){
User user = new User();
user.setId(2L);
//不需要显示地注入UserMapper
User user1 = user.selectById();
System.out.println(user1);
}
通过上面的结果可以看到,执行时间为5ms。如果将maxTime设置为1,那么,该操作会抛出如下异常。
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: The SQL execution time is too large, please optimize !
### The error may exist in cn/itcast/mp/mapper/UserMapper.java (best guess)
### The error may involve cn.itcast.mp.mapper.UserMapper.selectById
### The error occurred while handling results
### SQL: SELECT id,user_name,password,name,age,email FROM tb_user WHERE id=?
### Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: The SQL execution time is too large, please optimize !
7.4.乐观锁插件
7.4.1.乐观锁介绍
(1)乐观锁的目的在于当要更新一条记录的时候,希望这条记录没有被别人更新。 (2)乐观锁实现方式: ① 取出记录时,获取当前version ② 更新时,带上这个version ③ 执行更新时, set version = newVersion where version = oldVersion ④ 如果version不对,则更新失败
7.4.2.插件配置方式在以下三种方式中任选其一进行配置即可。 (1)在SpringBoot项目的自定义配置类中进行配置
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
(2)在Spring的配置文件中进行配置
(3)在Mybatis的全局配置文件mybatis-config.xml中进行配置
7.4.3.注解实体字段
(1)为tb_user表添加version字段,并且设置初始值为1
ALTER TABLE `tb_user` ADD COLUMN `version` int(10) NULL AFTER `email`;
UPDATE `tb_user` SET `version`='1';
(2)为User实体对象添加version字段,并且添加@Version注解
//乐观锁的版本字段
@Version
private Integer version;
7.4.4.编写测试代码
@Test
public void testUpdateVersion(){
User user = new User();
user.setId(2L);// 查询条件
User userVersion = user.selectById();
user.setAge(23); // 更新的数据
user.setVersion(userVersion.getVersion()); // 当前的版本信息
boolean result = user.updateById();
System.out.println("result => " + result);
}
(1)版本version支持的数据类型只有:int、Integer、long、Long、Date、Timestamp、LocalDateTime。 (2)整数类型下 newVersion = oldVersion + 1 (3)newVersion 会回写到 entity 中 (4)仅支持 updateById(id) 与 update(entity, wrapper) 方法 (5)在 update(entity, wrapper) 方法下, wrapper 不能复用!
8.Sql 注入器在MP中,通过AbstractSqlInjector将BaseMapper中的方法注入到了Mybatis容器,这样这些方法才可以正常执行。那么,如果需要扩充BaseMapper中的方法,又应该如何实现呢?下面将以扩展findAll方法为例进行展开学习。
8.1.编写MyBaseMapperpackage cn.itcast.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
public interface MyBaseMapper extends BaseMapper {
//扩充的方法
List findAll();
}
8.2.编写MySqlInjector
如果直接继承AbstractSqlInjector的话,那么原有的BaseMapper中的方法将失效,所以这里选择继承DefaultSqlInjector进行扩展。
package cn.itcast.mp.injectors;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import java.util.ArrayList;
import java.util.List;
public class MySqlInjector extends DefaultSqlInjector {
@Override
public List getMethodList() {
List list = new ArrayList();
// 获取父类中的集合
list.addAll(super.getMethodList());
// 再扩充自定义的方法
list.add(new FindAll());
return list;
}
}
8.3.编写FindAll
package cn.itcast.mp.injectors;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class FindAll extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) {
String sql = "select * from " + tableInfo.getTableName();
SqlSource sqlSource = languageDriver.createSqlSource(configuration,sql, modelClass);
return this.addSelectMappedStatement(mapperClass, "findAll", sqlSource, modelClass, tableInfo);
}
}
8.4.注册到Spring容器中
在SpringBoot的自定义的配置类中配置MySqlInjector(即将MySqlInjector注册到Spring容器中)
/**
* 注入自定义的SQL注入器
* @return
*/
@Bean
public MySqlInjector mySqlInjector(){
return new MySqlInjector();
}
8.5.编写测试方法
如果继续使用userMapper来进行测试,那么要将其继承的接口改为自定义的MyBaseMapper。
package cn.itcast.mp.mapper;
import cn.itcast.mp.pojo.User;
public interface UserMapper extends MyBaseMapper {
}
具体的测试方法如下:
@Test
public void testFindAll(){
List users = this.userMapper.findAll();
for (User user : users) {
System.out.println(user);
}
}
结果如下:
有些时候我们可能会有这样的需求,插入或者更新数据时,希望有些字段可以自动填充数据,比如密码、version等。在MP中提供了这样的功能,可以实现自动填充。
9.1.添加@TableField注解例如,为User类中的password添加自动填充功能,在新增数据时有效。
//插入数据时进行填充
@TableField(fill = FieldFill.INSERT)
private String password;
此外,FieldFill提供了以下多种模式选择:
package com.baomidou.mybatisplus.annotation;
/**
* 字段填充策略枚举类
*
*
* 判断注入的 insert 和 update 的 sql 脚本是否在对应情况下忽略掉字段的 if 标签生成
* ......
* 判断优先级比 {@link FieldStrategy} 高
*
*
* @author hubin
* @since 2017-06-27
*/
public enum FieldFill {
/**
* 默认不处理
*/
DEFAULT,
/**
* 插入时填充字段
*/
INSERT,
/**
* 更新时填充字段
*/
UPDATE,
/**
* 插入和更新时填充字段
*/
INSERT_UPDATE
}
9.2.编写MyMetaObjectHandler
package cn.itcast.mp.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入数据时填充
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
// 先获取到password的值,再进行判断,如果为空,就进行填充,如果不为空,就不做处理
Object password = getFieldValByName("password", metaObject);
if(null == password){
setFieldValByName("password", "888888", metaObject);
}
}
/**
* 更新数据时填充
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
}
}
9.3.编写测试用例
@Test
public void testInsert() {
User user = new User();
user.setUserName("xiaoli");
//不设置密码
user.setName("小李");
user.setAge(21);
user.setEmail("xiaoli@itcast.com");
//result:数据库受影响的行数
int result = this.userMapper.insert(user);
System.out.println("result => " + result);
//获取自增长后的id值, 自增长后的id值会回填到user对象中
System.out.println("id => " + user.getId());
}
开发系统时,有时候在实现功能时,删除操作需要实现逻辑删除,所谓逻辑删除就是将数据标记为删除,而并非真正的物理删除(非DELETE操作),查询时需要携带状态条件,确保被标记的数据不被查询到。这样做的目的就是避免数据被真正的删除。MP就提供了这样的功能,下面将展开介绍。
10.1.修改表结构为tb_user表增加deleted字段,用于表示数据是否被删除,1代表删除,0代表未删除。
ALTER TABLE `tb_user`
ADD COLUMN `deleted` int(1) NULL DEFAULT 0 COMMENT '1代表删除,0代表未删除'
AFTER `version`;
同时,也修改User实体,增加deleted属性并且添加@TableLogic注解
@TableLogic
private Integer deleted;
10.2.在application.properties中进行配置
# 删除状态的值为:1
mybatis-plus.global-config.db-config.logic-delete-value=1
# 未删除状态的值为:0
mybatis-plus.global-config.db-config.logic-not-delete-value=0
10.3.编写测试方法
@Test
public void testDeleteById(){
// 根据id删除数据(逻辑删除)
int result = this.userMapper.deleteById(2L);
System.out.println("result => " + result);
}
当id为2的用户被进行了逻辑删除后,再次查找该用户时则找不到
@Test
public void testSelectById() {
//根据id查询数据
User user = this.userMapper.selectById(2L);
System.out.println("result = " + user);
}
解决了繁琐的配置,让MyBatis更加方便地使用枚举属性!
11.1.修改表结构为tb_user表增加sex字段,用于表示用户地性别,1代表男,0代表女。
ALTER TABLE `tb_user`
ADD COLUMN `sex` int(1) NULL DEFAULT 1 COMMENT '1-男,2-女'
AFTER `deleted`;
11.2.定义枚举
package cn.itcast.mp.enums;
import com.baomidou.mybatisplus.core.enums.IEnum;
public enum SexEnum implements IEnum {
MAN(1,"男"),
WOMAN(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;
}
}
11.3.在application.properties中进行配置
# 枚举包扫描
mybatis-plus.type-enums-package=cn.itcast.mp.enums
11.4.修改实体类User
在User实体类中添加SexEnum字段
//性别,枚举类型
private SexEnum sex;
11.5.编写测试方法
(1)添加测试
@Test
public void testEnum(){
User user = new User();
user.setUserName("xiaofang");
user.setPassword("123456");
user.setAge(20);
user.setName("小芳");
user.setEmail("xiaofang@itcast.cn");
user.setVersion(1);
user.setSex(SexEnum.WOMAN); //使用的是枚举
// 调用AR的insert方法进行插入数据
boolean insert = user.insert();
System.out.println("result => " + insert);
}
(2)条件查询测试
@Test
public void testSelectBySex(){
QueryWrapper wrapper = new QueryWrapper();
wrapper.ge("sex", SexEnum.WOMAN)
.or()
.eq("age", 21)
.select("id","name","age"); //指定查询的字段
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper、XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
12.1.创建工程创建一个名为itcast-mp-generator的Maven工程
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.4.RELEASE
cn.itcast.mp
itcast-mp-generator
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-test
test
com.baomidou
mybatis-plus-boot-starter
3.1.1
com.baomidou
mybatis-plus-generator
3.1.1
org.springframework.boot
spring-boot-starter-freemarker
mysql
mysql-connector-java
5.1.47
org.slf4j
slf4j-log4j12
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-maven-plugin
12.3.生成器代码
package cn.itcast.mp.generator;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
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.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
/**
*
* mysql 代码生成器演示例子
*
*/
public class MysqlGenerator {
/**
*
* 读取控制台内容
*
*/
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.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
/**
* RUN THIS
*/
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("itcast");
gc.setOpen(false);
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("cn.itcast.mp.generator");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
List focList = new ArrayList();
focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输入文件名称
return projectPath + "/itcast-mp-generator/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
mpg.setTemplate(new TemplateConfig().setXml(null));
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseEntity");
strategy.setEntityLombokModel(true);
// strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");
strategy.setInclude(scanner("表名"));
strategy.setSuperEntityColumns("id");
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
// 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
运行上述的main方法即可自动生成代码。
MybatisX 是一款基于 IDEA 的快速开发插件,其目的在于提高开发效率。
13.1.安装方法打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入mybatisx 搜索并安装,安装之后重启IDEA即可使用该插件。
(1)Java 与 XML 调回跳转;
(2)Mapper 方法自动生成 XML;