
目录
MyBatis-Plus介绍
入门案例
CRUD基本方法
ActiveRecord
表与列
主键的类型
指定表名
指定列名
驼峰命名
自定义SQL
查询构造器(Wrapper)
条件列表
查询
分页查询
MP代码生成器
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文件依赖
org.springframework.boot spring-boot-startermysql mysql-connector-javaruntime org.springframework.boot spring-boot-starter-testtest
需要添加依赖
com.baomidou mybatis-plus-boot-starter3.4.3.4
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{ }
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) MapcolumnMap);
解析:
参数:表字段 map 对象
返回值:根据 columnMap 条件,删除记录
@Test
void testDeleteByMap(){
Map 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 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 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 list = new ArrayList<>();
list.add(6);
list.add(10);
List users = userMapper.selectBatchIds(list);
// SELECT id,name,age FROM user WHERe id IN ( ? , ? )
System.out.println("查询数据个数:" + users.size());
}
支持lambda表达式
@Test
void testSelectBatchById2(){
List list = Stream.of(6,10).collect(Collectors.toList());
List users = userMapper.selectBatchIds(list);
// SELECT id,name,age FROM user WHERe id IN ( ? , ? )
users.forEach(user -> {
System.out.println("查询的user对象:" + user);
});
}
条件查询,使用Map
ListselectByMap(@Param(Constants.COLUMN_MAP) Map columnMap);
解析;
参数:表字段,map对象
返回值:根据 columnMap 条件查询的List
@Test
void testSelectMap(){
Map map = new HashMap<>();
map.put("age",20);
List 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{ // 定义属性,属性名和表的列名一致 @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{ }
【注意】: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{ // 定义属性,属性名和表的列名一致 @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{ // 定义属性,属性名和表的列名一致 @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{ // 定义属性,属性名和表的列名一致 @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{ @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{ @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{ int insertUser(User user); }
在resources文件夹下,创建mapper文件夹,里面创建sql映射文件UserMapper.xml
insert into user (name,age) values (#{name},#{age})
这里注意以下,在类路径(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 表达式的构造查询条件。
条件列表使用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 baseMapperallEq{ }
基于map 的相等
map
@Test
void testAllEq(){
QueryWrapper qw = new QueryWrapper<>();
//组装条件
Map param = new HashMap<>();
// map key 列名,value:查询的值
param.put("name", "zhangsan");
param.put("age",22);
qw.allEq(param);
// 调用MP自己的查询方法
List 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 qw = new QueryWrapper<>();
// 组成条件
qw.eq("name", "zhangsan");
List 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 qw = new QueryWrapper<>();
qw.ne("name", "lisi");
List users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERe (name <> ?)
users.forEach(user -> System.out.println(user));
}
gt
大于 >
@Test
void testGt(){
QueryWrapper qw = new QueryWrapper<>();
qw.gt("age",20);
List 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 qw = new QueryWrapper<>();
qw.ge("age",20);
List users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERe (age >= ?)
users.forEach(user -> System.out.println(user));
}
lt
小于 <
@Test
void testLt(){
QueryWrapper qw = new QueryWrapper<>();
qw.lt("age",20);
List 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 qw = new QueryWrapper<>();
qw.le("age",20);
List 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 qw = new QueryWrapper<>();
qw.between("age",22,33);
List 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 qw = new QueryWrapper<>();
qw.notBetween("age",22,33);
List 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 qw = new QueryWrapper<>();
qw.like("name","z");
List 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 qw = new QueryWrapper<>();
qw.notLike("name","z");
List 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 qw = new QueryWrapper<>();
qw.likeLeft("name","z");
List 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 qw = new QueryWrapper<>();
qw.likeRight("name","z");
List 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 qw = new QueryWrapper<>();
qw.isNull("name");
List 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 qw = new QueryWrapper<>();
qw.isNotNull("name");
List 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 qw = new QueryWrapper<>();
qw.in("name","lisi","zhangsan");
List users = userMapper.selectList(qw);
// SELECT id,name,age FROM user WHERe (name IN (?,?))
users.forEach(user -> System.out.println(user));
}
@Test
void testIn2(){
QueryWrapper qw = new QueryWrapper<>();
ArrayList
notIn
不在值列表中
@Test
void testNoIn(){
QueryWrapper qw = new QueryWrapper<>();
qw.notIn("id",1,2);
List 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 qw = new QueryWrapper<>();
qw.inSql("age", "select age from user where id = 1");
List 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 qw = new QueryWrapper<>();
qw.notInSql("age", "select age from user where id = 1");
List 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 qw = new QueryWrapper<>();
qw.select("age, count(*) numbers"); // SELECT age, count(*) numbers
qw.groupBy("age");
List 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 qw = new QueryWrapper<>();
qw.orderByAsc("name","age");
List 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 qw = new QueryWrapper<>();
qw.orderByDesc("name","age");
List 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 qw = new QueryWrapper<>();
qw.orderBy(true,true,"age");
List users = userMapper.selectList(qw);
users.forEach(user -> System.out.println("查询结果:"+user));
}
可以使用链式编程的方式,实现多条件排序
@Test
void testOrder2(){
QueryWrapper qw = new QueryWrapper<>();
qw.orderBy(true,true,"age")
.orderBy(true,false,"name");
List 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 qw = new QueryWrapper<>();
qw.eq("name","zhangsan")
.or()
.eq("age",22);
List 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 qw = new QueryWrapper<>();
qw.eq("name","zhangsan")
.or()
.eq("age",22)
.last("limit 1");
List 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 qw = new QueryWrapper<>();
qw.exists("select id from user where age > 20");
List 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 qw = new QueryWrapper<>();
qw.notExists("select id from user where age > 20");
List 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 qw = new QueryWrapper<>();
qw.gt("age","15");
IPage page = new Page<>();
page.setCurrent(2); //第一页
page.setSize(3); // 设置每页记录条数
// 还可以设置其他参数
IPage userPage = userMapper.selectPage(page, qw);
// 获取分页后的记录
List 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 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖:
com.baomidou mybatis-plus-generator3.4.1 org.apache.velocity velocity-engine-core2.3
上面的模板引擎,是MyBatis-plus默认支持的,还有一些其他模板引擎,如:Freemarker、Beetl,用户可以选择自己熟悉的模板引擎,如果都不满足您的要求,可以采用自定义模板引擎。
Freemarker模板依赖
org.freemarker freemarkerlatest-freemarker-version
Beetl模板依赖
com.ibeetl beetllatest-beetl-version
注意!如果您选择了非默认引擎,需要在 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);
}
}
可以去官网查看其他信息:连接
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)