【MyBatis-Plus】快速入门
一、快速入门
入门案例制作步骤:
(1)新建模块并导入mybatis-plus起步依赖
<!-- mybatis-plus起步依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.10</version>
</dependency>
(2)编写application.yml文件
server:
port: 8080
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/mybatis-plus?useSSL=false
username: root
password: 123456
# mybatis-plus日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
(3)根据数据库表字段新建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
}
(4)编写mapper接口并测试查看运行结果
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 没有写任何接口方法
}
@SpringBootTest
class Demo1ApplicationTests {
@Autowired
private UserMapper mapper;
@Test
public void contextLoads() {
// 测试查询全部
List<User> users = mapper.selectByMap(null);
System.out.println(users);
}
}
Mybatis-Plus(简称MP)是基于Mybatis框架基础上开发的增强型工具,旨在简化开发,提高效率。mybatis-plus官网或mybatis-plus
MybatisPlus特性 |
---|
无侵入:只做增强不做改变 |
强大的CRUD操作:内置通用Mapper,少量配置即可实现单表CRUD操作 |
支持Lambda:编写查询条件无需担心字段写错 |
内置分页查询 |
支持主键自动生成 |
@SpringBootTest
class MybatisPlus1ApplicationTests {
@Autowired
private UserMapper mapper;
@Test
public void testUserMapper() {
// 查询所有
List<User> users = mapper.selectByMap(null);
System.out.println(users);
}
/**
* 测试添加操作
* 对于自增的字段:如果没有设置,则自动生成一个值;
* 对于非自增字段:如果可以为空,不生成;如果不可以为空,报错。
*/
@Test
public void insert() {
User user = new User();
user.setId(3L);
user.setName("sesssok");
user.setPassword("1333");
user.setAge(3);
int i = mapper.insert(user);
System.out.println(i);
}
/**
* 测试删除操作
*/
@Test
public void delete() {
// 批量删除--
// (Collection接口下有set、list、queue三个接口)根据id删除
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
mapper.deleteBatchIds(list);
// 根据map对象删除-根据某个字段删除
Map map = new HashMap();
map.put("age", 23);
mapper.deleteByMap(map);
}
/**
* 测试修改操作
*/
@Test
public void update() {
User user = new User();
user.setId(3L);
user.setAge(19);
// 修改所有
// mapper.update();
// 根据id修改
int i = mapper.updateById(user);
System.out.println(i);
}
}
下面是核心接口,附上源码和注释:
public interface BaseMapper<T> extends Mapper<T> {
// 插入一条记录
int insert(T entity);
// 根据id删除
int deleteById(Serializable id);
// 将map中的元素设置为删除的条件,多个条件之间是AND关系
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
// 将实体对象进行封装,包装为删除条件(类似上面)
int delete(@Param("ew") Wrapper<T> queryWrapper);
// 根据id集合批量删除
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
// 根据id更新
int updateById(@Param("et") T entity);
// 根据条件更新,Wrapper是条件
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
// 根据id查询
T selectById(Serializable id);
// 根据id(ids)批量查询
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
// 根据键值查询
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
// 根据实体条件查询一个,如果查到多个,就会报错
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
// 条件查询总记录数
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
// 条件查询集合
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
// 条件查询map集合
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
// 分页查询
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
配置分页插件:
@Configuration
public class MpConfig {
/**
* 设置Mybatis-Plus可以使用分页功能的插件
* @return
*/
@Bean
public MybatisPlusInterceptor interceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
调用分页方法并查看测试结果:
/**
* 测试分页
*/
@Test
public void testPage() {
IPage page = new Page();
page.setCurrent(1); // 设置当前页码
page.setSize(5); // 设置每页显示数
mapper.selectPage(page, null);
System.out.println("当前页码-->" + page.getCurrent() + ",每页显示数-->" + page.getSize());
System.out.println("总页数-->" + page.getPages() + ",总记录数-->" + page.getTotal() + ",数据-->" + page.getRecords());
}
查询条件格式 | 使用QueryWrappe泛型类 | 使用QueryWrapper泛型类+lambda | 使用LambdaQueryWrapper泛型类 |
---|---|---|---|
(1)新建一个模块
(2)导入MyBatis-Plus相关依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.10</version>
</dependency>
(3)使用方法
@SpringBootTest
class Demo1ApplicationTests {
@Autowired
private UserMapper mapper;
@Test
public void testSelectCon1() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.lt("age",20); // 查询age<20的记录
System.out.println(mapper.selectList(wrapper));
}
@Test
public void testSelectCon2() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.lambda().lt(User::getAge,20);
System.out.println(mapper.selectList(wrapper));
}
@Test
public void testSelectCon() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.lt(User::getAge,20);
System.out.println(mapper.selectList(wrapper));
}
}
并列关系 | 或者关系 |
---|---|
默认(.and()) | .or() |
@Test
public void testSelectCon4() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.lt(User::getAge, 18).or();
wrapper.gt(User::getAge, 20); // age<18 || age>20
// 链式写法1--or
wrapper.lt(User::getAge, 18).or()
.gt(User::getAge, 20); // age<18 || age>20
// 链式写法2--and
wrapper.gt(User::getAge, 10).lt(User::getAge, 18); // age>18 && age<18
System.out.println(mapper.selectList(wrapper));
}
(4)在yml配置文件设置关闭mybati-plus和SpringBoot的banner图案
# spring--banner: off
main:
banner-mode: off
# mybatis-plus--banner: false
mybatis-plus:
global-config:
banner: false
(5)新建logback.xml文件清除日志
# 标准日志输出
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
上面的输出不利于我们调试代码,因此在yml文件中添加如上代码,使控制台输出相关日志。
如果查询条件为空还出现在了Sql语句中,就会报错,要先使用null != __ 判断
(1)实体类和测试用例
@Data
public class QueryUser extends User{
/**
* 定义年龄范围的上限
*/
private Integer ageGt;
}
@Test
public void testNull() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
QueryUser user = new QueryUser();
// user.setAge(18); // 设置年龄下限
user.setAgeGt(20); // 设置年龄上限
wrapper.gt(User::getAge,user.getAge());
wrapper.lt(User::getAge,user.getAgeGt());
mapper.selectList(wrapper);
}
(2)运行结果
(3)解决方案-在查询之前加入条件判定再查看SQL语句
wrapper.gt(null != user.getAge(), User::getAge, user.getAge());
wrapper.lt(null != user.getAgeGt(), User::getAge, user.getAgeGt());
条件 | 等于 | 范围 | 模糊 |
---|---|---|---|
表达 | eq | lt,le,gt,ge,eq,between | like,likeLeft,likeRight(左右表示百分号的位置) |
通过查看官方文档了解更多查询条件的用法——MyBatis-Plus条件构造器官网链接。
举例:
@Test
public void testSelectCon5() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.between(User::getAge, 19, 25); // 查询age>=19 && age<=25的数据
mapper.selectList(wrapper);
wrapper.like(User::getUsername, "s"); // %s%
mapper.selectList(wrapper);
wrapper.likeRight(User::getPassword, "ll"); // ll%
}
情况 | 属性名和字段名不同 | 有些属性不在表中 | 有些字段不参与查询 | 实体类名和表名不同 |
---|---|---|---|---|
映射@TableFiled | value = “字段名” | exist =false | select = false | @TableName(“”) |
/**
* 用户名
*/
@TableField("name") // 1.字段名为name
private String username;
/**
* 密码
*/
@TableField(select = false) // 3.不参与查询
private String password;
/**
* 在线状态
*/
@TableField(exist = false) // 2.不存在
private Integer online;
id生成策略 | Auto | Input | Assign |
---|---|---|---|
使用 | 数据库定义一个id起始,然后+1 | 用户定义编写一个id | 用雪花算法生成一个Long值,默认策略 |
(1)自定义id自增
@Test
public void testId() {
User user =new User();
user.setUsername("DemoQ");
user.setPassword("WWER");
user.setAge(20);
mapper.insert(user); // 插入一条记录并查看id
}
(2)默认生成的Id
(3)自定义Id
@Test
public void testId() {
User user =new User();
user.setId(20L);
user.setUsername("DemoQ");
user.setPassword("WWER");
user.setAge(20);
mapper.insert(user); // 插入一条记录并查看id
}
可以再yml文件中全局配置id生成策略,这样就不用写@TableId注解,配置表名前缀,不用写@TableName的前缀注解。
# mybatis-plus--banner: false
mybatis-plus:
global-config:
banner: false
db-config:
id-type: assign_id # 使用默认的id生成策略
table-prefix: tb_ # 设置表名前缀,类名 = 表名-前缀
# 标准日志输出
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
这里主要通过两个API,deleteBatchIds(),selectBatchIds()来讲解多数据操作。
@Test
public void testMore() {
List<Long> list = new ArrayList<>();
list.add(5L);
list.add(6L);
mapper.selectBatchIds(list); // 批量查询
}
@Test
public void testMoreDelete() {
List<Long> list = new ArrayList<>();
list.add(20L);
list.add(27L);
mapper.deleteBatchIds(list); // 批量删除
}
通过字段(通常叫deleted)标记数据是否可用,不是执行真的删除,而是执行修改。之后查询时,MyBatis-Plus的所有查询操作都只查询没有被逻辑删除的数据。
设置逻辑删除字段 | @TableLogic() | yml配置 |
---|
执行删除操作之后再次查看表中数据:
步骤:
(1)数据库表中添加version字段,用于标记版本
(2)实体类中添加相应的字段并添加@Version注解
(3)添加拦截器实现动态添加sql语句
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor interceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
// 乐观锁拦截器
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
(4)模拟乐观锁version自增+1(执行更新操作前必须提前告知version版本)
法一:设置版本
@Test
public void testOptimisticLock() {
User user = new User();
user.setId(5L);
user.setAge(33);
user.setVersion(1);
mapper.updateById(user);
}
法二:通过id得到版本
@Test
public void testOptimisticLock2() {
User user = mapper.selectById(6);
user.setUsername("123");
mapper.updateById(user);
}
模板+配置=代码生成器
(1)导入模板生成器和模板引擎坐标
<!-- 代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
(2)配置数据库连接信息和其他配置
注意这里配置的数据库信息不是用于增删改查,而是用于创建实体类等。
public class CodeGenerator {
public static void main(String[] args) {
/**
* 基础配置
*/
AutoGenerator generator = new AutoGenerator();
DataSourceConfig config = new DataSourceConfig(); // 配置数据库连接相关信息
config.setDbType(DbType.MYSQL);
config.setDriverName("com.mysql.cj.jdbc.Driver");
config.setUrl("jdbc:mysql://localhost:3306/mybatis-plus?useSSL=false");
config.setUsername("root");
config.setPassword("123456");
generator.setDataSource(config);
/**
* 设置全局配置
*/
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java"); // 指定生成的代码模板目录
globalConfig.setAuthor("XiaoGuo"); // 设置作者
globalConfig.setOpen(false); // 设置生成代码后是否打开目录
globalConfig.setControllerName("%sController"); // 设置Controller文件名
globalConfig.setFileOverride(true); // 设置文件覆盖
globalConfig.setMapperName("%sMapper"); // 设置mapper层文件名
globalConfig.setIdType(IdType.ASSIGN_ID); // 设置ID生成策略
generator.setGlobalConfig(globalConfig);
/**
* 设置包名相关配置
*/
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.itxiaoguo"); // 设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
generator.setPackageInfo(packageConfig);
/**
* 策略设置
*/
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setInclude("tb_user"); // 设置要生成的表名,如果有多个,则叠加
strategyConfig.setTablePrefix("tb_"); // 设置表前缀名,生成的=表名-前缀
strategyConfig.setRestControllerStyle(true); // 生成的controller使用rest风格
strategyConfig.setEntityLombokModel(true); // 实体类使用Lombok注解
strategyConfig.setLogicDeleteFieldName("deleted"); // 设置逻辑删除字段名
strategyConfig.setVersionFieldName("version"); // 设置乐观锁字段名
generator.setStrategy(strategyConfig);
/**
* 执行生成操作
*/
generator.execute();
}
}
至此,MyBatis-Plus快速入门结束。
- 点赞
- 收藏
- 关注作者
评论(0)