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);
    }
相关推荐
zquwei7 分钟前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
TT哇13 分钟前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
火烧屁屁啦36 分钟前
【JavaEE进阶】初始Spring Web MVC
java·spring·java-ee
w_31234541 小时前
自定义一个maven骨架 | 最佳实践
java·maven·intellij-idea
岁岁岁平安1 小时前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA1 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
Q_19284999061 小时前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
张国荣家的弟弟1 小时前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi
ZSYP-S2 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos2 小时前
C++----------函数的调用机制
java·c++·算法