目录
MyBatis-Plus介绍
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 MyBatis-Plus 在MyBatis 之上套了一层外衣,单表CURD 的操作几乎都可以由 MyBatis-Plus 代替执行。而且提供了各种查询方式,分页行为。作为使用者无需编写xml,直接调用MyBatis-Plus 提供的API 就可以了。支持lambda表达式。底层是基于动态代理实现的。
官网:连接
入门案例
创建数据库mp ,创建user表,方便测试,数据库版本mysql8.X
将主键id设置为自增。
附加建表语句
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(80) COLLATE utf8mb4_general_ci DEFAULT NULL,
`age` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
创建一个SpringBoot项目,pom.xml文件依赖
<dependencies>
<!-- SpringBoot起步依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- mysql连接器依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- SpringBoot测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
需要添加依赖
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.4</version>
</dependency>
application.yml 添加数据库配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/数据库名?serverTimezone=GMT%2B8&&useUnicode=true&&characterEncoding=utf8&&useSSL=false&&nullCatalogMeansCurrent=true
username: 数据库用户名
password: 数据库密码
可以配置一个日志,方便程序的调试
# 添加日志,打印到控制台
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
这个日志,只会打印到控制台上,方便调试程序。
创建一个实体类User
public class User {
// 定义属性名:属性名与表中列名一致
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private Integer age;
// set get toString方法
}
解析:
@TableId:设置主键的方式:
value:主键字段的名称, 如果是id,可以不用写
type:指定主键的类型,主键的值如何生成,IdType.AUTO:表示自动增长。
自定义一个Mapper接口,实现BaseMapper,使用泛型指定实体类
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.km.model.User;
public interface UserMapper extends BaseMapper<User> {
}
BaseMapper 是MP框架中的对象,定义十几个CRUD操作方法.
需要在SpringBoot启动类上加入MapperScan注解,指定扫描的Mapper包,下面的案例也都需要。
@MapperScan("com.km.mapper")
@SpringBootApplication
public class MybatisPlusApplication {
public static void main(String[] args) { SpringApplication.run(MybatisPlusApplication.class, args);
}
}
在测试类中,以添加为例测试
@SpringBootTest
class MybatisPlusApplicationTests {
@Resource
private UserMapper userMapper;
@Test
void testUserInsert() {
User user = new User();
user.setName("zhangsan");
user.setAge(20);
int insert = userMapper.insert(user);
System.out.println("insert 的结果:" + insert);
}
}
注意:这个注入UserMapper对象,使用的自动注入的方式
如果使用 @Autowired 注解,会出现下面这种现象
出现这种错误的原因,是因为找不到bean对象,因为这个bean是在程序执行过程中,才会创建的。
解决这个问题需要在方法上,添加一个@SuppressWarnings 注解,用来抑制警告
@SuppressWarnings("all") // 抑制警告
测试结果也符合预期。
CRUD基本方法
insert
与入门案例类似,下面只介绍需要改动的地方,打开日志,便于测试。
int insert(T entity);
解析:
参数:实体类
返回值:插入的行数
// 添加数据后,获取主键值
@Test
void testUserInsertGetId() {
User user = new User();
user.setName("李四");
user.setAge(25);
int insert = userMapper.insert(user);
// INSERT INTO user ( name, age ) VALUES ( ?, ? )
System.out.println("insert 的结果:" + insert);
Integer id = user.getId();
System.out.println("主键的值:"+id);
}
不仅可以添加一条数据,还可以返回添加这条数据的主键值。
测试与预期一致。
update
根据主键值更新
int updateById(@Param(Constants.ENTITY) T entity);
解析:
参数:实体对象
返回值:修改的数据条数
@Test
void testUpdateUser(){
User user = new User();
user.setAge(36);
user.setName("张三");
// 根据主键值更新
user.setId(2);
int result = userMapper.updateById(user);
// UPDATE user SET name=?, age=? WHERE id=?
System.out.println("更新行数:" + result);
}
【注意】:更新属性,只更新非null字段的属性。下面案例:
@Test
void testUpdateUser2(){
User user = new User();
// 这里没有给age属性赋值
user.setName("22");
// 根据主键值更新
user.setId(1);
int result = userMapper.updateById(user);
// UPDATE user SET name=? WHERE id=?
System.out.println("更新行数:" + result);
}
解析:因为底层对非空进行了判断处理。判断字段是否要修改,是根据属性值是否为null判断。
【注意】如果实体类是基本数据类型,如:int,就会改变数据库的数据值,变为0。
这就和属性的默认值有关系,如果是包装类型,默认值就会是null,底层就会对null进行判断处理,而int类型默认值是0。因此,属性类型推荐使用包装类型。
delete
根据主键删除一条数据
int deleteById(Serializable id);
解析:
参数:主键
返回值:删除的行数
@Test
void testDeleteById(){
int row = userMapper.deleteById(2);
// DELETE FROM user WHERE id=?
System.out.println("删除行数:" + row);
}
【注意】:删除条件封装在Map 中,key 是列名,value 是值,多个key 之间and 联接。
下面方法与上个方法类似
int deleteById(T entity);
解析:
参数:实体类
返回值:删除的行数
@Test
void testDeleteById(){
User user = new User();
user.setId(1);
int row = userMapper.deleteById(user);
// DELETE FROM user WHERE id=?
System.out.println("删除行数:" + row);
}
按条件删除,使用Map
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
解析:
参数:表字段 map 对象
返回值:根据 columnMap 条件,删除记录
@Test
void testDeleteByMap(){
Map<String, Object> map = new HashMap<>();
map.put("age",25);
int result = userMapper.deleteByMap(map);
// DELETE FROM user WHERE age = ?
System.out.println("删除条数:" + result);
}
批处理方式,使用多个主键值,删除数据
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
解析:
参数:主键列表(不能为 null 以及 实体类)
返回值:根据ID 批量删除成功的条数
@Test
void testDeleteBatchById(){
List<Integer> list = new ArrayList<>();
list.add(7);
list.add(8);
list.add(9);
int result = userMapper.deleteBatchIds(list);
// DELETE FROM user WHERE id IN ( ? , ? , ? )
System.out.println("删除条数:" + result);
}
mybatis-plus支持lambda表达式
@Test
void testDeleteBatchById(){
// 使用lambda创建List集合
List<Integer> list = Stream.of(7, 8, 9).collect(Collectors.toList());
int result = userMapper.deleteBatchIds(list);
// DELETE FROM user WHERE id IN ( ? , ? , ? )
System.out.println("删除条数:" + result);
}
select
根据主键值查询
T selectById(Serializable id);
解析:
参数:主键值
返回值:实体类
@Test
void testSelectById(){
User user = userMapper.selectById(7);
// SELECT id,name,age FROM user WHERE id=?
System.out.println("查询 信息:" + user);
}
【注意】:如果根据主键没有查找到数据,返回值是null,不会报错。需要在使用对象之前,进行非空判断。
批处理查询,根据多个主键值查询,获取到List
解析:
参数:主键值列表(不能为 null 以及 实体类)
返回值:根据主键值列表,批量查询List
@Test
void testSelectBatchById(){
List<Integer> list = new ArrayList<>();
list.add(6);
list.add(10);
List<User> users = userMapper.selectBatchIds(list);
// SELECT id,name,age FROM user WHERE id IN ( ? , ? )
System.out.println("查询数据个数:" + users.size());
}
支持lambda表达式
@Test
void testSelectBatchById2(){
List<Integer> list = Stream.of(6,10).collect(Collectors.toList());
List<User> users = userMapper.selectBatchIds(list);
// SELECT id,name,age FROM user WHERE id IN ( ? , ? )
users.forEach(user -> {
System.out.println("查询的user对象:" + user);
});
}
条件查询,使用Map
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
解析;
参数:表字段,map对象
返回值:根据 columnMap 条件查询的List
@Test
void testSelectMap(){
Map<String, Object> map = new HashMap<>();
map.put("age",20);
List<User> users = userMapper.selectByMap(map);
// SELECT id,name,age FROM user WHERE age = ?
users.forEach(user -> {
System.out.println("查询的user对象:"+user);
});
}
ActiveRecord
介绍:
-
每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中 表的一行记录; 通常表的每个字段在类中都有相应的Field;
-
ActiveRecord 负责把自己持久化。在 ActiveRecord 中封装了对数据库的访 问,通过对象自己实现CRUD,实现优雅的数据库操作。
-
ActiveRecord 也封装了部分业务逻辑。可以作为业务对象使用。
这里的案例与入门案例大体上类似,数据库mp,表user,SpringBoot项目,mybatis-plus依赖,mysql连接器依赖,配置数据库信息,打开日志配置,也可以直接按照下面的更改入门案例。
创建User实体类,并继承Model,使用泛型指定实体类
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.extension.activerecord.Model;
public class User extends Model<User> {
// 定义属性,属性名和表的列名一致
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private Integer age;
// set get toString方法
}
【注意】:使用AR,要求实体类需要继承MP中的Model,Model中提供了对数据库的CRUD的操作。
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.km.model.User;
public interface UserMapper extends BaseMapper<User> {
}
【注意】:UserMapper 是不需要使用的,但是MP需要使用UserMapper获取到数据库的表的信息。如果不定义UserMapper,MP会报错,找不到表的定义信息。
AR-insert
调用实体对象自己的方法,完成对象自身到数据库的添加操作。
public boolean insert() {}
@Test
void testARInsert(){
// 定义User实体类
User user = new User();
user.setName("张三");
user.setAge(23);
boolean flag = user.insert();
// INSERT INTO user ( name, age ) VALUES ( ?, ? )
System.out.println("结果:" + flag);
}
添加成功返回true,失败返回false。
AR-update
根据主键更新数据
public boolean updateById() {}
@Test
void testARUpdate(){
User user = new User();
user.setId(14);
user.setAge(20);
user.setName("lisi");
boolean flag = user.updateById(); // 使用user实体类主键的值,WHERE id=14
// UPDATE user SET name=?, age=? WHERE id=?
System.out.println("结果:"+ flag);
}
更新成功返回true,失败返回false。
【注意】:属性值为null不做更新处理,update SQL语句中没有null的字段。
AR-delete
根据主键值,删除数据
public boolean deleteById(Serializable id) {}
@Test
void testARDeleteById(){
User user = new User();
boolean flag = user.deleteById(14);
// DELETE FROM user WHERE id=?
System.out.println("结果:"+flag);
}
删除数据成功返回true,删除失败返回false。
根据对象自身主键属性的值
public boolean deleteById() {}
@Test
void testARDeleteById2(){
User user = new User();
user.setId(15);
boolean flag = user.deleteById();
// DELETE FROM user WHERE id=?
System.out.println("结果:"+flag);
}
AR-selete
使用查询操作,需要实体类继承Model类时,添加泛型,方便操作。
根据主键查找数据,带参数
public T selectById(Serializable id) {}
@Test
void testARSelectById(){
User user = new User();
// 设置主键的值
user.setId(16);
//调用查询方法
User user1 = user.selectById();
// SELECT id,name,age FROM user WHERE id=?
System.out.println("查询结果:" + user1);
}
【注意】:按实体的主键能查找出数据,返回对象,如果查询不到数据,返回null。
根据主键查找数据,不带参数
public T selectById() {}
@Test
void testARSelectById(){
User user = new User();
// 设置主键的值
user.setId(16);
//调用查询方法
User user1 = user.selectById();
// SELECT id,name,age FROM user WHERE id=?
System.out.println("查询结果:" + user1);
}
表与列
主键的类型
public enum IdType {
AUTO(0),
NONE(1),
INPUT(2),
ASSIGN_ID(3),
ASSIGN_UUID(4);
}
解析:
AUTO:数据库ID自增
NONE:无状态
INPUT:插入前自行设置主键值
ASSIGN_ID:雪花算法
ASSIGN_UUID:排除中划线的UUID
AUTO,自动增长,前面案例用到过了
ASSIGN_ID(雪花算法)
如果不设置类型值,默认则使用IdType.ASSIGN_ID策略(自3.3.0起)。该策略会使用雪花算法自动生成主键ID,主键类型为长或字符串(分别对应的MySQL的表字段为BIGINT和VARCHAR)。
雪花算法(雪花)是分布式ID生成算法其核心思想就是:使用一个64位的长型的数字作为全局唯一ID。在分布式系统中的应用十分广泛,且ID引入了时间戳,基本上保持自增的。
修改实体类,主键类型
public class User extends Model<User> {
// 定义属性,属性名和表的列名一致
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Integer id;
private String name;
private Integer age;
// set get toString方法
}
更改数据库,与实体类对应
主键不需要自增。向数据库表中执行insert操作
上面这种类型是bigint类型,还可以使用varchar类型。
ASSIGN_UUID(排除中划线的UUID)
使用IdType.ASSIGN_UUID策略,并重新自动生成排除中划线的UUID作为主键。主键类型为String,对应MySQL的表分段为VARCHAR(32)
修改实体类
public class User extends Model<User> {
// 定义属性,属性名和表的列名一致
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
private String name;
private Integer age;
// set get toString方法
}
更改数据库,与实体类对应
主键不需要自增。向数据库表中执行insert操作
指定表名
定义实体类,默认的表名和实体类同名;如果不一致,在实体类定义上面使用@TableName 说明表名称。
@TableName(value="表名")
解析:在类的上面使用
属性value 指定表的名字。
现在表的名字为 user_test,与实体类的名字不一致,使用@TableName注解,指定表的名字。
@TableName(value = "user_test")
public class User extends Model<User> {
// 定义属性,属性名和表的列名一致
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private Integer age;
//set get toString方法
}
执行insert语句,向数据库添加数据,底层执行
INSERT INTO user_test ( name, age ) VALUES ( ?, ? )
这里就不是使用默认的user表,而是指定的user_test表。
指定列名
实体类属性名和表的列名不一致的情况下,在实体类属性上面使用@TableField 说明表的列名。
@TableField(value = "列名")
解析:在实体类属性的上面使用
属性value 指定表的列名。
现在表的名字为user,但是表的列名与实体类属性不一致
使用@TableField注解,指定表的列名的名字。
public class User extends Model<User> {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@TableField(value = "user_name")
private String name;
@TableField(value = "user_age")
private Integer age;
// set get toString方法
}
执行insert语句,向数据库添加数据,底层执行
INSERT INTO user ( user_name, user_age ) VALUES ( ?, ? )
这里就不是使用默认的实体类的属性名,而是指定的表的列名。
驼峰命名
列名使用下划线,属性名是驼峰命名方式。这种方式是比较常见的,mybatis-plus 默认支持这种规则。
表user,列名使用 "_" 进行分隔。
实体类,属性名使用驼峰命名的方式。
public class User extends Model<User> {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String userName; //user_name
private Integer userAge; //user_age
//set get toString方法
}
执行insert语句,向数据库添加数据,底层执行
INSERT INTO user ( user_name, user_age ) VALUES ( ?, ? )
自定义SQL
与入门案例类似,user表
实体类
public class User {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private Integer age;
// set get toString方法
}
创建UserMapper接口,实现BaseMapper,指定泛型,自定义mapper方法(mybatis的mapper),这里简单写一个插入语句,简单演示
public interface UserMapper extends BaseMapper<User> {
int insertUser(User user);
}
在resources文件夹下,创建mapper文件夹,里面创建sql映射文件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">
<mapper namespace="com.km.mybatis_plus.mapper.UserMapper">
<insert id="insertUser">
insert into user (name,age) values (#{name},#{age})
</insert>
</mapper>
这里注意以下,在类路径(resources文件夹)下,建立一个mapper文件夹,这个mapper文件夹下的xml文件都会自动扫描,无需配置。
如果不成功可以在application.yml配置文件中配置
mybatis-plus:
mapper-locations: classpath:mapper/*Mapper.xml
解析:这是指定mapper文件的位置。
测试这个方法
@SpringBootTest
class MybatisPlusCustomSQLTests {
@Resource
private UserMapper userMapper;
@Test
void testInsertUser(){
User user = new User();
user.setName("zhansgan");
user.setAge(22);
int result = userMapper.insertUser(user);
// insert into user (name,age) values (?,?)
System.out.println("结果:" + result);
}
}
测试结果符合预期。
查询构造器(Wrapper)
分类:
-
QueryWrapper:查询条件封装类
-
UpdateWrapper:更新条件封装类
QueryWrapper(LambdaQueryWrapper) 和UpdateWrapper(LambdaUpdateWrapper) 的父类用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件。 MP3.x 开始支持lambda 表达式,LambdaQueryWrapper,LambdaUpdateWrapper支持lambda 表达式的构造查询条件。
条件列表
条件 | 说明 |
---|---|
allEq | 基于map 的相等 |
eq / ne | 等于(=) / 不等于(<>) |
gt / ge / lt / le | 大于(>) / 大于等于(>=) / 小于(<) / 小于等于(<=) |
between / notBetween | BETWEEN 值1 AND 值2 / NOT BETWEEN 值1 AND 值2 |
like / notLike | LIKE '%值%' / NOT LIKE '%值%' |
likeLeft / likeRight | LIKE '%值' / LIKE '值%' |
isNull / isNotNull | 字段 IS NULL / 字段 IS NOT NULL |
in / notIn | 字段 IN (value1, value2, ...) / 字段 NOT IN (value1, value2, ...) |
inSql / notInSql | 字段 IN ( sql 语句 ) / 字段 NOT IN ( sql 语句 ) |
groupBy | GROUP BY 字段 |
orderByAsc / orderByDesc | 升序ORDER BY 字段, ... ASC / 降序ORDER BY 字段, ... DESC |
orderBy | 自定义字段排序 |
having | 条件分组 |
or | OR 语句,拼接 + OR 字段=值; |
and | AND 语句,拼接 + AND 字段=值 |
apply | 拼接 sql |
last | 在sql 语句后拼接自定义条件 |
exists / notExists | 拼接 EXISTS (sql 语句) / 拼接 NOT EXISTS (sql 语句) |
nested | 正常嵌套 不带 AND 或者 OR |
查询
使用user表,主键设置为自增。
实体类User
public class User {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private Integer age;
// set get toString方法
}
创建UserMapper接口,实现BaseMapper,指定泛型类型
public interface UserMapper extends BaseMapper<User> {
}
allEq
基于map 的相等
map<key,value> key 列名,value:查询的值
@Test
void testAllEq(){
QueryWrapper<User> qw = new QueryWrapper<>();
//组装条件
Map<String, Object> param = new HashMap<>();
// map<key,value> key 列名,value:查询的值
param.put("name", "zhangsan");
param.put("age",22);
qw.allEq(param);
// 调用MP自己的查询方法
List<User> users = userMapper.selectList(qw);
users.forEach(user -> System.out.println(user));
}
底层执行sql,使用占位符的格式,参数“张三”,22 替换
SELECT id,name,age FROM user WHERE (name = ? AND age = ?)
allEq(map,boolean)
解析:第二个参数,是Boolean值
true:处理null值, where 条件加入 字段 is null。
底层行sql语句
SELECT id,name,age FROM user WHERE (name = ? AND age IS NULL)
false:忽略null, 不作为where 条件。
底层行sql语句
SELECT id,name,age FROM user WHERE (name = ?)
eq
等于 =
eq(R column, Object val){}
解析:
column:列名
val:值
@Test
void testEq(){
QueryWrapper<User> qw = new QueryWrapper<>();
// 组成条件
qw.eq("name", "zhangsan");
List<User> users = userMapper.selectList(qw);
users.forEach(user -> System.out.println(user));
}
底层执行SQL
SELECT id,name,age FROM user WHERE (name = ?)
ne
不等于 <>
ne(R column, Object val){}
解析:
column:列名
val:值
@Test
void testNe(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.ne("name", "lisi");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (name <> ?)
users.forEach(user -> System.out.println(user));
}
gt
大于 >
@Test
void testGt(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.gt("age",20);
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (age > 20)
users.forEach(user -> System.out.println(user));
}
ge
大于等于 >=
@Test
void testGe(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.ge("age",20);
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (age >= ?)
users.forEach(user -> System.out.println(user));
}
lt
小于 <
@Test
void testLt(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.lt("age",20);
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (age < 20)
users.forEach(user -> System.out.println(user));
}
le
小于等于 <=
@Test
void testLe(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.le("age",20);
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (age <= ?)
users.forEach(user -> System.out.println(user));
}
between
between("列名",开始值,结束值)
@Test
void testBetween(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.between("age",22,33);
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (age BETWEEN ? AND ?)
// where age >= 22 and age <= 33
users.forEach(user -> System.out.println(user));
}
notBetween
notBetween("列名",开始值,结束值)
@Test
void testNotBetween(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.notBetween("age",22,33);
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (age NOT BETWEEN 22 AND 33)
// where age < 22 and age > 33
users.forEach(user -> System.out.println(user));
}
like
"%值%"
@Test
void testLike(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.like("name","z");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (name LIKE ?)
// SELECT id,name,age FROM user WHERE (name LIKE %z%)
users.forEach(user -> System.out.println(user));
}
notLike
@Test
void testNotLike(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.notLike("name","z");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (name NOT LIKE ?)
// SELECT id,name,age FROM user WHERE (name NOT LIKE %z%)
users.forEach(user -> System.out.println(user));
}
likeLeft
"%值"
@Test
void testLikeLeft(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.likeLeft("name","z");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (name LIKE ?)
// SELECT id,name,age FROM user WHERE (name LIKE %z)
users.forEach(user -> System.out.println(user));
}
likeRight
"值%"
@Test
void testLikeRight(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.likeRight("name","z");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (name LIKE ?)
// SELECT id,name,age FROM user WHERE (name LIKE z%)
users.forEach(user -> System.out.println(user));
}
isNull
判断字段是 null
@Test
void testIsNull(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.isNull("name");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (name IS NULL)
users.forEach(user -> System.out.println(user));
}
isNotNull
判断字段是 is not null
@Test
void testIsNotNull(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.isNotNull("name");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (name IS Not NULL)
users.forEach(user -> System.out.println(user));
}
in
in("列名", 多个值的列表)
@Test
void testIn(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.in("name","lisi","zhangsan");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (name IN (?,?))
users.forEach(user -> System.out.println(user));
}
@Test
void testIn2(){
QueryWrapper<User> qw = new QueryWrapper<>();
ArrayList<Object> list = new ArrayList<>();
list.add(1);
list.add(2);
qw.in("id",list);
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (id IN (1,2))
users.forEach(user -> System.out.println(user));
}
notIn
不在值列表中
@Test
void testNoIn(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.notIn("id",1,2);
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (id NOT IN (?,?))
users.forEach(user -> System.out.println(user));
}
inSql
使用子查询
@Test
void testIsSql(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.inSql("age", "select age from user where id = 1");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (age IN (select age from user where id = 1))
users.forEach(user -> System.out.println(user));
}
notInSql
使用子查询
@Test
void testNotIsSql(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.notInSql("age", "select age from user where id = 1");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (age Not IN (select age from user where id = 1))
users.forEach(user -> System.out.println(user));
}
groupBy
分组
@Test
void testGroupBy(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.select("age, count(*) numbers"); // SELECT age, count(*) numbers
qw.groupBy("age");
List<User> users = userMapper.selectList(qw);
// SELECT age, count(*) numbers FROM user GROUP BY age
users.forEach(user -> System.out.println("查询结果:"+user));
}
orderByAsc
按字段升序
@Test
void testOrderByAsc(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.orderByAsc("name","age");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user ORDER BY name ASC,age ASC
users.forEach(user -> System.out.println("查询结果:"+user));
}
orderByDesc
按字段降序
@Test
void testOrderByDesc(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.orderByDesc("name","age");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user ORDER BY name DESC,age DESC
users.forEach(user -> System.out.println("查询结果:"+user));
}
order
指定字段和判断方法
orderBy(boolean condition, boolean isAsc, R column) {}
解析:
condition : 条件是否加入到 SQL语句的后面
-
true:表示加入到SQL语句后面
SELECT id,name,age FROM user ORDER BY age ASC
-
false:表示不加入sql语句的后面
SELECT id,name,age FROM user ORDER BY age ASC
isAsc:条件是否是升序排序
-
true:表示升序排序
SELECT id,name,age FROM user ORDER BY age ASC
-
false:表示降序排序
SELECT id,name,age FROM user ORDER BY age DESC
@Test
void testOrder(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.orderBy(true,true,"age");
List<User> users = userMapper.selectList(qw);
users.forEach(user -> System.out.println("查询结果:"+user));
}
可以使用链式编程的方式,实现多条件排序
@Test
void testOrder2(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.orderBy(true,true,"age")
.orderBy(true,false,"name");
List<User> users = userMapper.selectList(qw);
// age asc, name desc
// SELECT id,name,age FROM user ORDER BY age ASC,name DESC
users.forEach(user -> System.out.println("查询结果:"+user));
}
and, or
条件连接作用,默认是and
@Test
void testOr(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("name","zhangsan")
.or()
.eq("age",22);
List<User> users = userMapper.selectList(qw);
// ELECT id,name,age FROM user WHERE (name = ? OR age = ?)
users.forEach(user -> System.out.println("查询结果:"+user));
}
last
拼接SQL语句到MP的SQL语句的结尾
@Test
void testLast(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("name","zhangsan")
.or()
.eq("age",22)
.last("limit 1");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (name = ? OR age = ?) limit 1
users.forEach(user -> System.out.println("查询结果:"+ user));
}
exists
判断条件,拼接 EXISTS(sql语句)
@Test
void testExists(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.exists("select id from user where age > 20");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (EXISTS (select id from user where age > 20))
users.forEach(user -> System.out.println("查询结果:"+user));
}
notExists
与exists操作相反
@Test
void testNotExists(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.notExists("select id from user where age > 20");
List<User> users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERE (NOT EXISTS (select id from user where age > 20))
users.forEach(user -> System.out.println("查询结果:"+user));
}
分页查询
需要配置一个配置类
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
这里使用的是mysql数据库,DbType.MYSQL。
需要扫描Mapper包
@MapperScan("com.km.mybatis_plus.mapper")
简单测试
@Test
void testPage(){
QueryWrapper<User> qw = new QueryWrapper<>();
qw.gt("age","15");
IPage<User> page = new Page<>();
page.setCurrent(2); //第一页
page.setSize(3); // 设置每页记录条数
// 还可以设置其他参数
IPage<User> userPage = userMapper.selectPage(page, qw);
// 获取分页后的记录
List<User> users = userPage.getRecords();
for (User user : users){
System.out.println("查询:"+user);
}
}
【底层分页步骤】,以上面案例为例
1.统计符合条件的记录条数
SELECT COUNT(*) AS total FROM user WHERE (age > ?)
2.实现分页,在sql语句结尾加上 limit ?,?
SELECT id,name,age FROM user WHERE (age > ?) LIMIT ?,?
注意:如果是显示第一页,limit后面只有一个占位符。
Page类的一些默认配置
public Page() {
this.records = Collections.emptyList();
this.total = 0L;
this.size = 10L;
this.current = 1L;
this.orders = new ArrayList();
this.optimizeCountSql = true;
this.searchCount = true;
this.optimizeJoinOfCountSql = true;
}
MP代码生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
MyBatis-Plus 从 3.0.3
之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖:
<!-- 代码生成器 依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!-- Velocity 模板引擎 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
上面的模板引擎,是MyBatis-plus默认支持的,还有一些其他模板引擎,如:Freemarker、Beetl,用户可以选择自己熟悉的模板引擎,如果都不满足您的要求,可以采用自定义模板引擎。
Freemarker模板依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>latest-freemarker-version</version>
</dependency>
Beetl模板依赖
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
<version>latest-beetl-version</version>
</dependency>
注意!如果您选择了非默认引擎,需要在 AutoGenerator 中 设置模板引擎。
AutoGenerator generator = new AutoGenerator();
// set freemarker engine
generator.setTemplateEngine(new FreemarkerTemplateEngine());
// set beetl engine
generator.setTemplateEngine(new BeetlTemplateEngine());
// set custom engine (reference class is your custom engine class)
generator.setTemplateEngine(new CustomTemplateEngine());
// other config
创建AutoMapper类,用来生成代码
// 代码生成器
public class AutoMapper {
public static void main(String[] args) {
// 创建AutoGenerator, MP中的对象
AutoGenerator autoGenerator = new AutoGenerator();
// 设置全局变量
// 设置数据源DataSource
// 设置Package信息
// 设置策略
// 执行代码生成
autoGenerator.execute();
}
}
设置全局变量
// 设置全局变量
GlobalConfig globalConfig = new GlobalConfig();
// 设置代码生成的位置,磁盘的位置
globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");
// 设置生成Mapper的名称
globalConfig.setMapperName("%sMapper"); // 例如:UserMapper,都是以Mapper结尾
// 设置生成Service接口的名称
globalConfig.setServiceName("%sService"); // 例如:UserService
// 设置生成Service实现类的名称
globalConfig.setServiceImplName("%sServiceImpl"); // 例如:UserServiceImpl
// 设置生成Controller类的名称
globalConfig.setControllerName("%sController"); // UserController
// 设置作者
globalConfig.setAuthor("123");
// 配置主键ID类型
globalConfig.setIdType(IdType.AUTO);
// 将GlobalConfig配置加入AutoGenerator
autoGenerator.setGlobalConfig(globalConfig);
设置数据源DataSource
// 设置数据源DataSource
DataSourceConfig dataSourceConfig = new DataSourceConfig();
// 设置驱动
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
// 设置url
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/数据库名?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false&&nullCatalogMeansCurrent=true");
// 设置数据库的用户名
dataSourceConfig.setUsername("账号");
// 设置密码
dataSourceConfig.setPassword("密码");
// 将DataSourceConfig配置加入AutoGenerator
autoGenerator.setDataSource(dataSourceConfig);
设置Package信息
// 设置Package信息
PackageConfig packageConfig = new PackageConfig();
// 设置模块名,相当于包名
packageConfig.setModuleName("auto");
// 设置父包名
packageConfig.setParent("com.km"); // com.km.auto
// 将PackageConfig配置加入AutoGenerator
autoGenerator.setPackageInfo(packageConfig);
设置策略
// 设置策略
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setNaming(NamingStrategy.underline_to_camel);
// 设置支持驼峰命名
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
// 将StrategyConfig配置加入AutoGenerator
autoGenerator.setStrategy(strategyConfig);
附加代码生成器执行目录
简单测试
@SpringBootTest
class MybatisPlusAutoTests {
@Resource
private UserMapper userMapper;
@Test
void testAuto(){
User user = new User();
user.setAge(55);
user.setName("张三");
int insert = userMapper.insert(user);
System.out.println("结果:"+insert);
}
}
可以去官网查看其他信息:连接