一、快速入门
-
创建表结构
-
创建实体类【不用加
@AllArgsConstructor和@NoArgsConstructor注解】@Data public class User { private Long id; private String name; private String password; private Integer age; private String tel; } -
定义Mapper接口【只需继承BaseMapper就可以实现单表的 CRUD 操作】
@Mapper public interface UserMapper extends BaseMapper<User>{} -
【可选】为了方便观察MP框架执行的数据库操作,可以在application.yaml中配置MP的日志,将SQL输出到控制台
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启mp日志,将sql输出到控制台
二、BaseMapper常用方法
-
新增操作
@SpringBootTest public class MPTest{ @Resource private UserMapper userMapper; @Test void testInsert(){ User user = new User(); user.setName("张三"); user.setPassword("123456"); user.setAge(12); user.setTel("13812345678"); user.setOnline("1"); //调用BaseMapper中提供的insert方法 userMapper.insert(user); } } -
根据id删除【单个】
@SpringBootTest public class MPTest{ @Resource private UserMapper userMapper; @Test void testDeleteById(){ //根据id删除数据 int i = userMapper.deleteById(1624945956237721601L); } } -
根据id删除【批量】
@SpringBootTest public class MPTest{ @Resource private UserMapper userMapper; @Test void testDeleteBatchIds(){ int batchIds = userMapper.deleteBatchIds(Arrays.asList(1625061142848167937L, 1625061824372146177L)); } } -
根据id修改
@SpringBootTest public class MPTest{ @Resource private UserMapper userMapper; @Test void testUpdateById(){ User user=new User(); user.setId(2625307405933957121L); user.setName("张三"); int i=userMapper.updateById(user); } } -
根据id查询【单个】
@SpringBootTest public class MPTest{ @Resource private UserMapper userMapper; @Test void testSelectById(){ User user = userMapper.selectById(1625307405933957121L); } } -
根据id查询【批量】
@SpringBootTest public class MPTest{ @Resource private UserMapper userMapper; @Test void testSelectBatchIds(){ List<User> users = userMapper.selectBatchIds(Arrays.asList(1625307405933957121L, 1625310776384380930L)); } } -
分页查询
@SpringBootTest public class MPTest{ @Resource private UserMapper userMapper; @Test void testSelectPage(){ //分页查询条件对象 Page<User> page = new Page<>(1,5); //分页查询 userMapper.selectPage(page,null); //总记录数 long total = page.getTotal(); //分页结果数据 List<User> records = page.getRecords(); } }需要提前配置MP框架的分页拦截器
package com.suenchi.config; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MPConfiguration { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); //添加分页拦截器,实现分页查询功能 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return mybatisPlusInterceptor; } }
三、常用注解
-
@TableName:映射实体类和表的对应关系@TableName("t_user") public class User{ private Long id; //...... }以下情况MP会自动进行映射,注解
@TableName可以省略:- 类名和表名一致
- 类名采用驼峰命名法(UserOptLog),表名使用对应的下划线分割命名(user_opt_log)
-
@TableField:映射实体类属性和表字段的对应关系public class User{ //当前属性对应的字段为pwd @TableField(value="pwd") private String password; //当前属性在表中没有对应的字段 @TableField(exist=false) private String online; }-
相关属性
- value:设置表字段名称
- exist:设置属性在表字段中是否存在,默认为true
-
以下情况MP会自动进行映射,注解
@TableField可以省略:- 属性名和字段名一致
- 属性名采用驼峰命名法(CreateTime),字段名使用对应的下划线分割命名(create_time)
-
-
@TableId:映射实体类属性和表主键字段的对应关系,还能设置主键的生成策略public class User{ @TableId(type=IdType.AUTO) private Long id; }-
相关属性
- value:设置表主键字段名称
- type:设置主键的生成策略,值参照IdType的枚举值
-
主键生成策略
- AUTO:使用数据库id自增策略控制id生成
- NONE:不设置id生成策略
- INPUT:用户手工输入id
- ASSIGN_ID:雪花算法生成id(可兼容数值型与字符串型)
- ASSIGN_UUID:以UUID生成算法作为id生成策略
-
雪花算法:是Twitter公司推出的专门针对分布式ID的解决方案
-
为了简化开发,我们可以在application.yaml中配置全局的主键生成策略,之后在实体类中就无须再配置了
mybatis-plus: global-config: db-config: id-type: assign_id #全局设置主键生成策略
-
四、常用条件构造器
-
条件构造器,即Wrapper,其作用是控制最终生成的SQL语句的条件部分,如下:
select ___ from tb where ___ order by ___update tb set ___ where ___delete from tb where ___
-
常用Wrapper
-
QueryWrapper:控制最终生成的查询、删除类的SQL语句//条件构造器 QueryWrapper<User> queryWrapper=new QueryWrapper<>(); queryWrapper.select("id","name"); queryWrapper.gt("age",20); queryWrapper.eq(tel!=null,"tel",tel); //动态添加查询条件 queryWrapper.like("name","zhangsan"); queryWrapper.orderByAsc("id"); //执行查询 List<User> userList=userMapper.selectList(queryWrapper);- 以上对应的预编译SQL:
select id,name from user where age>? and tel=? and name like ? order by id asc - 使用QueryWrapper设置条件,其实是通过字符串指定的字段名,如果指定的字段名有误,在编译阶段不会报错,而在程序运行期间才会抛出异常
- 以上对应的预编译SQL:
-
LambdaQueryWrapper:为了解决QueryWrapper的问题而出现的,能保证在编译阶段就发现错误//条件构造器 LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper<>(); lambdaQueryWrapper.select(User::getId,User::getName); lambdaQueryWrapper.gt(User::getAge,20); lambdaQueryWrapper.eq(tel!=null,User::getTel,tel); //动态添加查询条件 lambdaQueryWrapper.like(User::getName,"itcast"); lambdaQueryWrapper.orderByAsc(User::getId); //执行查询 List<User> userList=userMapper.selectList(lambdaQueryWrapper);实际开发中,我们都用
LambdaQueryWrapper来取代QueryWrapper -
UpdateWrapper:控制最终生成的更新类的SQL语句//条件构造器 UpdateWrapper<User> updateWrapper=new UpdateWrapper<>(); updateWrapper.set("name","zhangsan"); updateWrapper.gt("age",18); //执行更新 userMapper.update(null,updateWrapper); //使用 BaseMapper 的 update 方法设置 set 条件时,既可以通过第一个参数(实体对象)设置,也可以通过第二个参数(UpdateWrapper)设置,这里是通过第二个参数设置的- 以上对应的预编译SQL:
update user set name=? where age>? - 同QueryWrapper,也是通过字符串指定的字段名,如果指定的字段名有误,在编译阶段不会报错,而在程序运行期间才会抛出异常
- 以上对应的预编译SQL:
-
LambdaUpdateWrapper:为了解决UpdateWrapper的问题而出现的,能保证在编译阶段就发现错误//条件构造器 LambdaUpdateWrapper<User> lambdaUpdateWrapper=new LambdaUpdateWrapper<>(); lambdaUpdateWrapper.set(User::getName,"zhangsan"); lambdaUpdateWrapper.gt(User::getAge,18); //执行更新 userMapper.update(null,lambdaUpdateWrapper);实际开发中,我们都用
LambdaUpdateWrapper来取代UpdateWrapper
-
-
【技巧】在定义条件构造器时,可以使用链式编程风格
QueryWrapper<User> queryWrapper=new QueryWrapper<>(); queryWrapper .select("id", "name") .gt("age", 20) .eq(tel != null, "tel", tel) .like("name", "zhangsan") .orderByAsc("id"); -
【扩展】为了进一步增强MyBatis的功能,我们可以在Mapper中声明方法时,利用MP提供的Wrapper条件构造器对象作为参数
@Mapper public interface UserMapper extends BaseMapper<User>{ @Select("select * from t_user ${ew.customSqlSegment}") List<User> findByCondition(@Param("ew") Wrapper<User> queryWrapper); }- 上述通过
@Param注解为Wrapper对象指定了别名, customSqlSegment为固定写法,底层会调用Wrapper对象的getCustomSqlSegment()方法获取对应的SQL片段
- 上述通过
五、MP 对 Service 层的支持
-
业务接口继承 MP 提供的 IService 接口
public interface UserService extends IService<User>{} -
业务实现类继承 MP 提供的 ServiceImpl类
@Service public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{} -
对于单表操作,直接调用 MP 提供的 Service 中的方法即可
-
当 MP 中 Service 中提供的方法不能满足要求时,可以自己扩展方法:
public interface UserService extends IService<User>{ public void myMethod(); }public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{ public void myMethod(){ //在业务实现类中,通过调用getBaseMapper方法能够获得对应的Mapper对象 UserMapper userMapper=this.getBaseMapper(); //业务... User user = userMapper.selectById(1625307405933957121L); } }在业务实现类中,通过调用getBaseMapper方法能够获得对应的Mapper对象
六、逻辑删除【扩展】
-
物理删除指的是直接将数据从数据库中删除,执行的是delete语句
-
逻辑删除指的是修改数据中的某个字段,使其表示为已删除状态,执行的是update语句
员工编号 姓名 工号 deleted 1 张三 9501 1 2 李四 9502 0 3 王五 9503 0 -
对于那些重要的、后期可能需要恢复的数据,可以考虑使用逻辑删除
-
MP 框架已经对逻辑删除提供了实现,我们直接使用即可
-
在表中添加逻辑删除字段 deleted
-
在 application.yaml 中配置逻辑删除相关配置项
mybatis-plus: global-config: db-config: logic-delete-field: deleted # 逻辑删除全局属性名 logic-delete-value: 1 # 逻辑删除全局值 logic-not-delete-value: 0 # 逻辑未删除全局值 -
在实体类中添加逻辑删除属性,并标识
@TableLogic注解@Data public class UserInfo{ private Long id; private String name; private Integer age; @TableLogic private Integer deleted; //删除标识:1已删除,0未删除 }
之后调用BaseMapper的删除方法时,发现底层调用的是update语句;调用查询方法时,会自动追加查询条件deleted=0
-
七、MyBatisX【扩展】
利用MaBatisX代码生成器,能根据表结构,反向生成对应的实体类、Mapper、Service等【参考其他文章】