Java_MyBatisPlus

MyBatisPlus属于是MyBatis的拓展,不影响原MyBatis框架下的代码运行,并对MyBatis框架进行拓展及优化。

使用步骤:

注意:继承BaseMapper时要填写泛型为要操作的实体类。

基本原理:

MyBatisPlus通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。

并且满足下面三点:

**·**类名驼峰转下划线作为表名

**·**名为id的字段作为主键

**·**变量名驼峰转下划线作为表的字段

(createTime -> create_time)

常见注解:

常见配置:

MyBatisPlus的配置项继承了MyBatis原生配置和一些自己特有的配置。例如:

注意:除去第一个别名扫描包,其他的配置在默认情况下就是这样配置的。

对MyBatis-Plus中的wrapper进行测试:

java 复制代码
    @Test
    void testLambdaQueryWrapper1() {
        //查询用户名中有"o"且余额为1000的用户的id、userName、info、balance
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<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);
    }

    @Test
    void testLambdaQueryWrapper2() {
        //更新jack的余额为2000
        User user = new User();
        user.setBalance(2000);
        LambdaQueryWrapper wrapper = new LambdaQueryWrapper<User>()
                .eq(User::getUsername, "jack");
        userMapper.update(user, wrapper);
    }

    @Test
    void testLambdaUpdateWrapper() {
        //更新id为1,2,4的用户的余额,扣200
        /*
        update set balance = balance - 200 where id in (1,2,4)
         */
        List<Long> ids = List.of(1L, 2L, 4L);
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<User>()
                .setSql("balance = balance - 200")
                .in(User::getId, ids);
        userMapper.update(null, wrapper);
    }

自定义SQL:

操作步骤:

Service接口:

使用流程:

实现下面接口:

代码:

Controller:
java 复制代码
@RestController
@RequestMapping("/users")
@Api(tags = "用户管理接口")
@RequiredArgsConstructor
public class UserController {

    private final IUserService userService;

    @ApiOperation("新增用户接口")
    @PostMapping
    public void save(@RequestBody UserFormDTO userDTO) {
        User user = BeanUtil.copyProperties(userDTO, User.class);
        userService.save(user);
    }

    @ApiOperation("删除用户接口")
    @DeleteMapping("/{id}")
    public void delete(@ApiParam("用户id") @PathVariable Long id) {
        userService.removeById(id);
    }

    @ApiOperation("根据id查询用户接口")
    @GetMapping("/{id}")
    public UserVO get(@ApiParam("用户id") @PathVariable Long id) {
        User user = userService.getById(id);
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        return userVO;
    }

    @ApiOperation("根据id批量查询接口")
    @GetMapping
    public List<UserVO> list(@ApiParam("用户id集合") @RequestParam("ids") List<Long> ids) {
        List<User> users = userService.listByIds(ids);
        List<UserVO> userVOS = BeanUtil.copyToList(users, UserVO.class);
        return userVOS;
    }

    @ApiOperation("根据id扣减余额接口")
    @PutMapping("/{id}/deduction/{money}")
    public void deductBalance(@ApiParam("用户id") @PathVariable Long id, @ApiParam("扣减金额") @PathVariable Integer money) {
        userService.deductBalance(id, money);
    }

}
Service:
java 复制代码
public interface IUserService extends IService<User> {
    void deductBalance(Long id, Integer money);
}
ServiceImpl:
java 复制代码
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Override
    public void deductBalance(@Param("id") Long id, @Param("money") Integer money) {
        //1.查询用户信息
        User user = getById(id);
        //2.判断用户状态
        if(user == null || user.getStatus() == 2) {
            throw new RuntimeException("用户状态异常!");
        }
        //3.判断用户余额
        if(user.getBalance() < money) {
            throw new RuntimeException("用户余额不足!");
        }
        //4.扣除余额
        baseMapper.deductBalance(id, money);
    }
}
Mapper:
java 复制代码
public interface UserMapper extends BaseMapper<User> {


    void updateBalanceByIds(@Param("ew") LambdaUpdateWrapper<User> wrapper, @Param("amount") int amount);

    @Update("update user set balance = balance - #{money} where id = #{id}")
    void deductBalance(Long id, Integer money);
}

Lambda查询:

lambda查询功能很强大,除去下面例题使用的list,还有查询一个时使用的one,分页查询使用的page,统计使用的count。

代码演示:

Controller:
java 复制代码
    @ApiOperation("根据复杂条件查询用户接口")
    @GetMapping("/list")
    public List<UserVO> queryUsers(UserQuery query) {
        //1.查询用户PO
        List<User> users = userService.queryUsers(query.getName(), query.getStatus(), query.getMinBalance(), query.getMaxBalance());
        //2.将PO拷贝到VO
        return BeanUtil.copyToList(users, UserVO.class);
    }
Service:
java 复制代码
List<User> queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance);
ServiceImpl:
java 复制代码
    @Override
    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();
    }

Lambda更新

代码演示:

Controller:
java 复制代码
    @ApiOperation("根据id扣减余额接口")
    @PutMapping("/{id}/deduction/{money}")
    public void deductBalance(@ApiParam("用户id") @PathVariable Long id, @ApiParam("扣减金额") @PathVariable Integer money) {
        userService.deductBalance(id, money);
    }
Service:
java 复制代码
void deductBalance(Long id, Integer money);
ServiceImpl:
java 复制代码
@Override
    public void deductBalance(@Param("id") Long id, @Param("money") Integer money) {
        //1.查询用户信息
        User user = getById(id);
        //2.判断用户状态
        if (user == null || user.getStatus() == 2) {
            throw new RuntimeException("用户状态异常!");
        }
        //3.判断用户余额
        if (user.getBalance() < money) {
            throw new RuntimeException("用户余额不足!");
        }
        //4.扣除余额
        int remainBalance = user.getBalance() - money;
        lambdaUpdate()
                .set(User::getBalance, remainBalance)
                .set(remainBalance == 0, User::getStatus, 2)
                .eq(User::getId, id)
                .eq(User::getBalance, user.getBalance())//乐观锁 先比较再更新
                .update();
    }

在业务层,如果两个线程同时查询同一个用户的信息,并且都扣除100余额,如果不进行加锁那么结果余额只会减少100,所以这里采用乐观锁,先比较数据库中的余额信息与查询到的用户余额信息是否一致,一致再更新数据。

批量新增:

批处理方案:

**·**普通for循环逐条插入,速度极差,不推荐

**·**MP的批量新增,基于预编译的批处理,性能不错

**·**配置jdbc的参数,设置rewriteBatchedStatements为true,性能最好

配置:

DB静态工具:

逻辑删除:

逻辑删除即删除数据时,通过修改一个特殊的字段值,来进行逻辑上的删除,而不是真正的删除数据,比如添加字段deleted,它为false即这条数据没被删除,它为true即这条数据被删除

问题:

枚举处理器:

实现PO类中枚举类型变量与数据库字段的转换:

User和UserVO:

java 复制代码
@Data
public class User {

    /**
     * 用户id
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;

    /**
     * 注册手机号
     */
    private String phone;

    /**
     * 详细信息
     */
    private String info;

    /**
     * 使用状态(1正常 2冻结)
     */
    private UserStatus status;

    /**
     * 账户余额
     */
    private Integer balance;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 更新时间
     */
    private LocalDateTime updateTime;
}
java 复制代码
@Data
@ApiModel(description = "用户VO实体")
public class UserVO {

    @ApiModelProperty("用户id")
    private Long id;

    @ApiModelProperty("用户名")
    private String username;

    @ApiModelProperty("详细信息")
    private String info;

    @ApiModelProperty("使用状态(1正常 2冻结)")
    private UserStatus status;

    @ApiModelProperty("账户余额")
    private Integer balance;

    @ApiModelProperty("用户的收货地址")
    private List<AddressVO> addresses;
}

①枚举类:

java 复制代码
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;
    }
}

②在配置文件中进行配置:

java 复制代码
mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

JSON处理器:

分页查询:

①先配置插件

java 复制代码
@Configuration
public class MyBatisConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //创建分页插件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInnerInterceptor.setMaxLimit(1000L);
        //添加分页插件
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;


    }

}

②使用插件:

PageQuery:
java 复制代码
@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {
    @ApiModelProperty("页码")
    private Long pageNo = 1L;
    @ApiModelProperty("页大小")
    private Long pageSize = 5L;
    @ApiModelProperty("排序字段")
    private String sortBy;
    @ApiModelProperty("是否升序")
    private Boolean isAsc = true;

    public <T> Page<T> toMpPage(OrderItem ... items) {
        //1.分页条件
        Page<T> page = Page.of(pageNo, pageSize);
        //2.排序条件
        if (StrUtil.isNotBlank(sortBy)) {
            //不为空
            page.addOrder(new OrderItem(sortBy, isAsc));
        } else if (items != null) {
            //为空,默认排序
            page.addOrder(items);
        }
        return page;
    }

    public <T> Page<T> toMpPage(String defaultSortBy, Boolean defaultAsc) {
        return toMpPage(new OrderItem(defaultSortBy, defaultAsc));
    }

    public <T> Page<T> toMpPageDefaultSortByCreateTime() {
        return toMpPage(new OrderItem("create_time", false));
    }

    public <T> Page<T> toMpPageDefaultSortByUpdateTime() {
        return toMpPage(new OrderItem("update_time", false));
    }

}
pageDTO:
java 复制代码
@Data
@ApiModel(description = "分页结果")
public class PageDTO<T> {
    @ApiModelProperty("总条数")
    private Long total;
    @ApiModelProperty("总页数")
    private Long pages;
    @ApiModelProperty("集合")
    private List<T> list;

    public static <PO, VO> PageDTO<VO> of(Page<PO> p, Class<VO> clazz) {
        PageDTO<VO> dto = new PageDTO<>();
        //1.总条数
        dto.setTotal(p.getTotal());
        //2.总页数
        dto.setPages(p.getPages());
        //3.当前页数据
        List<PO> records = p.getRecords();
        if(CollUtil.isEmpty(records)) {
            dto.setList(Collections.emptyList());
            return dto;
        }
        //4.拷贝user的VO
        dto.setList(BeanUtil.copyToList(records, clazz));
        //5.返回
        return dto;
    }

    public static <PO, VO> PageDTO<VO> of(Page<PO> p, Function<PO, VO> convertor) {
        PageDTO<VO> dto = new PageDTO<>();
        //1.总条数
        dto.setTotal(p.getTotal());
        //2.总页数
        dto.setPages(p.getPages());
        //3.当前页数据
        List<PO> records = p.getRecords();
        if(CollUtil.isEmpty(records)) {
            dto.setList(Collections.emptyList());
            return dto;
        }
        //4.拷贝user的VO
        dto.setList(records.stream().map(convertor).collect(Collectors.toList()));
        //5.返回
        return dto;
    }

}
Controller:
java 复制代码
    @ApiOperation("根据条件分页查询用户接口")
    @GetMapping("/page")
    public PageDTO<UserVO> queryUsersPage(UserQuery query) {
        return userService.pageUsersPage(query);
    }
Service:
java 复制代码
    PageDTO<UserVO> pageUsersPage(UserQuery query);
ServiceImpl:
java 复制代码
    @Override
    public PageDTO<UserVO> pageUsersPage(UserQuery query) {
        String name = query.getName();
        Integer status = query.getStatus();
        //1.构建分页条件
        Page<User> page = query.toMpPageDefaultSortByUpdateTime();
        //2.分页查询
        Page<User> p = lambdaQuery()
                .like(name != null, User::getUsername, name)
                .eq(status != null, User::getStatus, status)
                .page(page);
        //3.封装VO结果
        return PageDTO.of(p, UserVO.class);
    }
相关推荐
今天背单词了吗98014 分钟前
算法学习笔记:8.Bellman-Ford 算法——从原理到实战,涵盖 LeetCode 与考研 408 例题
java·开发语言·后端·算法·最短路径问题
天天摸鱼的java工程师17 分钟前
使用 Spring Boot 整合高德地图实现路线规划功能
java·后端
东阳马生架构32 分钟前
订单初版—2.生单链路中的技术问题说明文档
java
咖啡啡不加糖1 小时前
暴力破解漏洞与命令执行漏洞
java·后端·web安全
风象南1 小时前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
DKPT1 小时前
Java享元模式实现方式与应用场景分析
java·笔记·学习·设计模式·享元模式
Percep_gan1 小时前
idea的使用小技巧,个人向
java·ide·intellij-idea
缘来是庄1 小时前
设计模式之迭代器模式
java·设计模式·迭代器模式
Liudef061 小时前
基于HTML与Java的简易在线会议系统实现
java·前端·html
JosieBook1 小时前
【Java编程动手学】Java常用工具类
java·python·mysql