目录
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(){ Mapmap = 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(){ Listlist = 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集合 Listselectlist = Stream.of(7, 8, 9).collect(Collectors.toList()); int result = userMapper.deleteBatchIds(list); // DELETE FROM user WHERe id IN ( ? , ? , ? ) System.out.println("删除条数:" + result); }
根据主键值查询
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(){ Listlist = 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(){ Listlist = 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(){ MapActiveRecordmap = 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); }); }
介绍:
-
每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中 表的一行记录; 通常表的每个字段在类中都有相应的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(){ QueryWrapperqw = 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(){ QueryWrapperqw = 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(){ QueryWrappergtqw = 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)); }
大于 >
@Test void testGt(){ QueryWrappergeqw = 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)); }
大于等于 >=
@Test void testGe(){ QueryWrapperltqw = 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)); }
小于 <
@Test void testLt(){ QueryWrapperleqw = 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)); }
小于等于 <=
@Test void testLe(){ QueryWrapperbetweenqw = 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("列名",开始值,结束值)
@Test void testBetween(){ QueryWrappernotBetweenqw = 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("列名",开始值,结束值)
@Test void testNotBetween(){ QueryWrapperlikeqw = 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)); }
"%值%"
@Test void testLike(){ QueryWrappernotLikeqw = 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)); }
@Test void testNotLike(){ QueryWrapperlikeLeftqw = 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)); }
"%值"
@Test void testLikeLeft(){ QueryWrapperlikeRightqw = 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)); }
"值%"
@Test void testLikeRight(){ QueryWrapperisNullqw = 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)); }
判断字段是 null
@Test void testIsNull(){ QueryWrapperisNotNullqw = 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)); }
判断字段是 is not null
@Test void testIsNotNull(){ QueryWrapperinqw = 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("列名", 多个值的列表)
@Test void testIn(){ QueryWrapperqw = 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(){ QueryWrappernotInqw = new QueryWrapper<>(); ArrayList
不在值列表中
@Test void testNoIn(){ QueryWrapperinSqlqw = 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)); }
使用子查询
@Test void testIsSql(){ QueryWrappernotInSqlqw = 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)); }
使用子查询
@Test void testNotIsSql(){ QueryWrappergroupByqw = 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)); }
分组
@Test void testGroupBy(){ QueryWrapperorderByAscqw = 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)); }
按字段升序
@Test void testOrderByAsc(){ QueryWrapperorderByDescqw = 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)); }
按字段降序
@Test void testOrderByDesc(){ QueryWrapperorderqw = 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)); }
指定字段和判断方法
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(){ QueryWrapperqw = new QueryWrapper<>(); qw.orderBy(true,true,"age"); List users = userMapper.selectList(qw); users.forEach(user -> System.out.println("查询结果:"+user)); }
可以使用链式编程的方式,实现多条件排序
@Test void testOrder2(){ QueryWrapperand, orqw = 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
@Test void testOr(){ QueryWrapperlastqw = 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)); }
拼接SQL语句到MP的SQL语句的结尾
@Test void testLast(){ QueryWrapperexistsqw = 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(sql语句)
@Test void testExists(){ QueryWrappernotExistsqw = 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)); }
与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(){ QueryWrapperqw = 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条)