mybatis-plus Nuyoah 2024-03-08 2024-03-21 MybatisPlus入门
使用步骤
引入MybatisPlus的起步依赖
1 2 3 4 5 <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-boot-starter</artifactId > <version > 3.5.3.1</version > </dependency >
定义Mapper继承MybatisPlus提供的BaseMapper接口,需要提供泛型为你的泛型
1 2 3 public interface UserMapper extends BaseMapper <User>{ }
常见注解
MybatisPlus的约定
类名驼峰转下划线作为表名
名为id的字段作为主键
变量名驼峰转下划线作为表的字段名
如果表不满足当前的约定的话,MybatisPlus还提供了注解
@TableName:用来指定表名,类名和表明不一致的时候使用,如果不使用的话会出现,找不到表的情况
@Tableld(value=“主键名”, type=“IdType.AUTO, INPUT, ASSIGN_ID”):用来指定表中的主键字段信息
表的主键名不是id,需要我们自己使用该注解来表明id,一定要给给出表的id,否则MybatisPlus无法根据主键来进行增删改查
type中AUTO:自增长ID, INPUT:通过set方法自行输入,ASSIGN_ID:通过雪花算法生成ID
@TableField:用来指定表中的普通字段信息,属性名和表中的名字不同的时候使用
成员变最名与数据库字段名不一致
成员变最名以is开头“且是布尔值
成员变最名与数据库关键字冲突
成员变量不是数据库字段
MybatisPlus配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 mybatis-plus: type-aliases-package: com.nuyoah.domain.entity mapper-locations: classpath:mybatis/mapper/*.xml configuration: map-underscore-to-camel-case: true cache-enabled: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-not-delete-value: 0 logic-delete-field: deFlag logic-delete-value: 1 id-type: auto update-strategy: not_null
MybatisPlus核心
条件构造器
wrapper自定义构造语句,通过wapper对象来构造语句
1 2 3 SELECT id, username, info, balanceFROM user WHERE username LIKE ? AND balance >= ?
MybatisPlus
ge:>=
eq:=
QueryWapper:执行查询条件
1 2 3 4 5 6 7 8 9 10 void testWapper () { QueryWapper<User> wrapper = new QueryWrapper <User>() .select("id" , "username" , "info" , "balance" ) .like("username" , "o" ) .ge("balance" , 1000 ); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println) }
更新id为1,2,4的用户的余额,口200
UpdateWrapper:执行更新语句
1 2 3 4 5 6 7 8 9 10 void testWapper () { List<Long> ids = List.of(1L , 2L , 4L ); UpdateWrapper<User> wrapper = new UpdateWrapper <User>() .setSql("balance = balance-200" ) .in("id" , ids) userMapper.update(wrapper); }
LambdaQueryWrapper使用
QueryWrapper中使用了字符串作为参数,Lambda使用了变量来作为查询参数
1 2 3 4 5 6 7 8 9 10 void testWapper () { QueryWapper<User> wrapper = new QueryWrapper <User>() .select(User::getId, User::getUsername, User::getInfo, User::getBalance) .like(User::getUsername, "o" ) .ge(User::getBalance, 1000 ); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println) }
自定义SQL
使用MyBatisPlus的Wrapper来构建Sql中的Where条件,然后自己定义Sql中剩下的语句
基于Wrapper构建的where条件
1 2 3 4 5 6 7 8 9 void testWapper () { List<Long> ids = List.of(1L , 2L , 4L ); int amount = 200 LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper <User>().in(User::getid, ids) userMapper.updateBalanceByIds(wrapper, amount); }
在Mapper方法参数名中使用Param注解声明wrapper变量名称,必须是ew
1 void updateBalanceByIds (@Param("ew") LambdaQueryWrapper<User> wrapper, @Param("amount") int amount) ;
自定义sql,并使用wrapper条件,自己不用写复杂的where语句
1 2 3 <update id ="updateBalanceByIds" > UPDATE tb_user SET balance = balance - #{amount} ${ew.customSqlSegment} </update >
Service接口
先继承
我们自己的service类和serviceImpl类,可以继承IService和和IServiceImpl
使用方法
自定义Service接口继承IService接口
1 2 3 public interface IUserService extends IService <User>{ }
自定义Service实现类,实现自定义接口,并继承ServiceImpl类
1 2 3 public class UserServiceImpl extends ServiceImpl <UserMapper, User> implements IUserService { }
当我们实现自己的Controller的时候,自动注入Service组件的时候,SpingBoot会报错说,不支持这样注入
这时候可以使用注解
1 2 3 4 5 6 7 @RequireArgsConstructor public class UserController { private final IUserService userService; }
Service简单接口
新增:userService.save(user);
删除:userService.removeById(id)
查询:
查询单个:userService.getById(id)
查询多个:userService.list(ids)
Service复杂接口
对指定id的对象进行工资+200,需要我们手写SQL
UserService
1 2 3 public void deductBalance (Long id, Integer money) { baseMapper.deductBalance(id, money); }
UserMapper
1 2 @Update("update tb_user set balance = balance-#{money} where id =#{id}") void deductBalance (@Param("id") Long id, @Param("money") Integer money) ;
Lambda查询
可以实现复杂查询
不适用lambda时候的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <select id ="queryUsers" resultType ="com.itheima.mp.domain.po.User" > SELECT * FROM tb_user <where > <if test ="name != null" > AND username LIKE #{name} </if > <if test ="status != null" > AND `status` = #{status} </if > <if test ="minBalance != null and MaxBalance != null" > AND balance BETWEEN #{minBalance} AND #{maxBalance} </if > </where > </select >
使用Lambda时候的代码
1 2 3 4 5 6 7 8 public List<User> queryUsers (String name, Integer status, Integer minBalance, Integer maxBalance) { return lambdaQuery() .like(name != null , User::getUsername, name) .eq(status != null , User::getStatus, status) .ge(minBalance != null , User::getBalance, minBalance) .le(maxBalance != null , User::getBalance, maxBalance) .list() }
扣减余额,当余额为零的时候将用户status设置为2
1 2 3 4 5 6 7 8 public List<User> deduceBalance (Long id, Integer money) { int reaminBalance = user.getBalance() - money return lambdaUpdate() .set(User::getBalance, reaminBalance) .set(remainBalance == 0 , User::getStatus, 2 ) .eq(User::getId, id) .update() }
批量新增
MybatisPlus扩展功能
代码生成
MybatisPlus插件
静态工具
逻辑删除就是基于代码逻辑模拟删除效果,但并不会真正删除数据。思路如下
在表中添加一个字段标记数据是否被删除
当删除数据时把标记置为1
查询时只查询标记为0的数据
MybatisPlus提供了逻辑删除功能,无需改变方法调用的方式 ,而是在底层帮我们自动修改CRUD的语句。我们要做的就是在application.yaml文件中配置逻辑删除的字段名称和值即可 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 mybatis-plus: # 匿名域 type-aliases-package: com.nuyoah.domain.entity # mapper文件映射路径 mapper-locations: classpath:mybatis/mapper/*.xml configuration: # 日志文件 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true cache-enabled: true global-config: db-config: # 配置逻辑删除字段名 logic-delete-field: deFlag logic-not-delete-value: 0 logic-delete-value: 1 id-type: auto
枚举处理器
当我们在数据库中存在例如status状态标记的时候,可以使用enum来代替0和1,通过枚举处理器来将enum对应到数据库中的项
枚举类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Getter public enum UserStatus { NORMAL(1 , "正常" ), FROZEN(2 , "冻结" ), ; @EnumValue private final int value; private final String desc; UserStatus(int value, String desc){ this .value = value; this .desc = desc; } }
配置枚举处理器的配置
1 2 3 mybatis-plus: configuration: default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
实体类配置
1 2 3 4 public class User { private UserStatus status; }
status使用
1 user.getStatus() === UserStatus.FROZEN
使用@JsonValue来确定请求返回值是什么
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Getter public enum UserStatus { NORMAL(1 , "正常" ), FROZEN(2 , "冻结" ), ; @EnumValue private final int value; @JsonValue private final String desc; UserStatus(int value, String desc){ this .value = value; this .desc = desc; } }
JSON处理器
将数据库中的JSON字符串转成对象
1 2 3 4 5 6 7 8 @Data @TableName(value="user", autoResultMap=true) public class User { private Long id; private String username; @TableFiled(typeHandler = JacksonTypeHandler.class) private UserInfo info; }
MybatisPlus插件
TenantLineInnerInterceptor:多租户插件
DynamicTableNameInnerInterceptor:动态表名插件
PaginationInnerInterceptor:分页插件
OptimisticLockerInnerInterceptor:乐观锁插件
IllegalSQLInnerInterceptor:SQL性能规范插件,检测并拦截垃圾SOL
BlockAttackInnerInterceptor:防止全表更新和删除的插件
分页插件
创建分页插件类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import com.baomidou.mybatisplus.annotation.DbType;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 MyBatisConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor () { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor (); PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor (DbType.MYSQL); pageInterceptor.setMaxLimit(1000L ); interceptor.addInnerInterceptor(pageInterceptor); return interceptor; } }
分页API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 default <E extends IPage <T>> E page (E page, Wrapper<T> queryWrapper) { return getBaseMapper().selectPage(page, queryWrapper); } default <E extends IPage <T>> E page (E page) { return page(page, Wrappers.emptyWrapper) }
使用分页API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test void testPageQuery () { int pageNo = 1 , pageSize = 5 ; Page<User>page= Page.of(pageNo,pageSize); page.addOrder(new OrderItem ("balance" , false )); Page<User> p = userservice.page(page); System.out.println("total = " + p.getTotal()); System.out.println("pages = " + p.getPages()); List<User> records = p.getRecords(); records.forEach(System.out::printin); }