MybatisPlus核心功能-Service接口

1.IService接口基本用法

MybatisPlus提供了IServiceServiceImpl实现类,只需要将自己定义的相关Service和impl实现类分别继承即可直接使用其相关方法。

IService接口使用流程:

1.自定义Service并继承IService,并指定实体类

public interface IUserService extends IService<User> {
}

2.自定义Impl实体类并继承ServiceImpl,并传入相关Mapper和实体类

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}

测试类:

@SpringBootTest
class IUserServiceTest {

    @Autowired
    private  IUserService userService;

    @Test
    void testInsert() {
        User user = new User();
        user.setId(5L);
        user.setUsername("LiLei");
        user.setPassword("123");
        user.setPhone("18688990011");
        user.setBalance(200);
        user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        userService.save(user);
    }
    @Test
    void testQuery(){
        List<User> users = userService.listByIds(List.of(1L, 3L, 4L));
        users.forEach(System.out::println);
    }

}

2.IService开发基础业务接口 

不用写任何Service代码,直接调用MybatisPlus提供的Service方法实现。 

2.1引入Swagger依赖(方便单元测试)和Web依赖

<!--swagger-->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
    <version>4.1.0</version>
</dependency>
<!--web-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2.2需要在application.ymal中配置swagger信息

knife4j:
  enable: true
  openapi:
    title: 用户管理接口文档
    description: "用户管理接口文档"
    email: 1936543730@qq.com
    concat: zk
    url: 
    version: v1.0.0
    group:
      default:
        group-name: default
        api-rule: package
        api-rule-resources:
          - com.zk.mp.controller

2.3 然后进行开发,创建实体类Controller

@Data
public class User {

    /**
     * 用户id
     */
    private Long id;

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

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

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

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

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

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

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

    /**
     * 更新时间
     */
    private LocalDateTime updateTime;


}
@Data
@ApiModel(description = "用户表单实体")
public class UserFormDTO {

    @ApiModelProperty("id")
    private Long id;

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

    @ApiModelProperty("密码")
    private String password;

    @ApiModelProperty("注册手机号")
    private String phone;

    @ApiModelProperty("详细信息,JSON风格")
    private String info;

    @ApiModelProperty("账户余额")
    private Integer balance;
}
@Data
@ApiModel(description = "用户VO实体")
public class UserVO {

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

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

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

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

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

@Api(tags = "用户管理接口")
@RequestMapping("/users")
@RestController
@RequiredArgsConstructor
public class UserController {

    //@Autowired注入spring不推荐,而是推荐用注入函数来注入Service 可以用@RequiredArgsConstructor注解来自动调用函数注入Service
    private final IUserService userService;

    @ApiOperation("新增用户接口")
    @PostMapping
    public void saveUser(@RequestBody UserFormDTO userDTO) {
        //注:表单实体一般以JASON形式提交,用RequestBody,才能更好的接受JASON类型的参数

        //把DTO拷贝到PO(将DTO转为User)
        // 1. 创建新的User对象
        User user = new User();
        // 2. 将DTO的属性复制到User对象中
        BeanUtils.copyProperties(userDTO, user);
        // 3. 新增用户
        userService.save(user);
    }

    @ApiOperation("删除用户接口")
    @DeleteMapping("/{id}")
    public void deleteUserById(@ApiParam("用户id") @PathVariable("id") Long id) {
        //注:参数此时为路径参数,所以用@PathVariable注解,然后参数也需要用Swagger标注
        userService.removeById(id);
    }

    @ApiOperation("根据id查询用户接口")
    @GetMapping("/{id}")
    public UserVO queryUserById(@ApiParam("用户id") @PathVariable("id") Long id) {
        //注:参数此时为路径参数,所以用@PathVariable注解,然后参数也需要用Swagger标注
        //1.查询用户PO
        User user = userService.getById(id);//查一个用get,查一群用list
        //2.把PO拷贝到VO
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);
        return userVO; //User 是从数据库中查询出来的实体对象,包含了所有字段。
        //UserVO 是要返回给前端的对象,只包含前端需要的字段。
        //通过 BeanUtils.copyProperties(user, userVO),可以将 User 中的属性复制到 UserVO,但不会包含 User 中可能存在的敏感字段或其他不需要的字段。
    }

    @ApiOperation("根据id批量查询用户接口")
    @GetMapping
    public List<UserVO> queryUserByIds(@ApiParam("用户id集合") @RequestParam("ids") List<Long> ids) {
        //1. 查询用户PO
        List<User> users = userService.listByIds(ids);

        //2. 把PO拷贝到VO列表
        List<UserVO> userVOList = new ArrayList<>();
        for (User user : users) {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            userVOList.add(userVO);
        }
        return userVOList;
    }
}

 3.IService开发复杂业务接口

 并不是所有业务都能直接调用MabatisPlus实现,当需要实现复杂业务功能需要自定义SQL语句时,我们需要自定义Service方法,并且调用我们的自定义Mapper,然后自定义SQL语句,实现功能。

@Api(tags = "用户管理接口")
@RequestMapping("/users")
@RestController
@RequiredArgsConstructor
public class UserController {

    //@Autowired注入spring不推荐,而是推荐用注入函数来注入Service 可以用@RequiredArgsConstructor注解来自动调用函数注入Service
    private final IUserService userService;

    @ApiOperation("扣减用户余额接口")
    @PutMapping("/{id}/deduction/{money}")
    public void deductMoneyById(@ApiParam("用户id") @PathVariable("id") Long id,
                                @ApiParam("扣减的金额") @PathVariable("money") Integer money) {
        userService.deductMoneyById(id);
    }
}
public interface IUserService extends IService<User> {
    void deductBalanceById(Long id,Integer money);
}
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Override
    public void deductBalanceById(Long id, Integer money) {
        //1.查询用户
        User user=getById(id);     //继承了IService,故不用注入IUserService,可以直接调用mp方法获取用户
        //2.校验用户状态
        if(user==null || user.getStatus()==2){
            throw new RuntimeException("用户状态异常");
        }
        //3.校验余额是否充分
        if(user.getBalance()< money){
            throw new RuntimeException("用户余额不足");
        }
        // 4.扣减余额 update tb_user set balance =balance-?
        baseMapper.deductBalance(id,money);  //自定义语句要用Mapper
    }
}
public interface UserMapper extends BaseMapper<User> {

   @Update("UPDATE tb_user SET balance =balance- #{money} WHERE id=#{id}")
    void deductBalance(@Param("id") Long id, @Param("money") Integer money);
}

 SQL语句可以在UserMapper中用注解直接写,也可以在Mapper.xml文件中写。

业务功能完成,接下来就可以使用Postman或其他工具进行测试接口。

4.IService的Lambda方法

是ISerice提供的非常方便的查询方法。

 

 

实现: 
当查询参数过多可以定义一个对象来接收查询参数。

@Data
@ApiModel(description = "用户查询条件实体")
public class UserQuery {
    @ApiModelProperty("用户名关键字")
    private String name;
    @ApiModelProperty("用户状态:1-正常,2-冻结")
    private Integer status;
    @ApiModelProperty("余额最小值")
    private Integer minBalance;
    @ApiModelProperty("余额最大值")
    private Integer maxBalance;
}
@Api(tags = "用户管理接口")
@RequestMapping("/users")
@RestController
@RequiredArgsConstructor
public class UserController {

    @ApiOperation("根据复杂条件查询用户接口")
    @GetMapping("/list")
    public List<UserVO> queryUserByIds(UserQuery query) {
        //当查询参数过多可以定义一个对象来接收查询参数 get类请求参加可以不加任何注解,直接用对象接收
        //1. 查询用户PO
        List<User> users = userService.queryUsers(query.getName(), query.getStatus(), query.getMinBalance(), query.getMaxBalance());

        //2. 把PO拷贝到VO列表
        return BeanUtil.copyToList(users, UserVO.class);//BeanUtil导入的工具类是hutool
    }
}
public interface IUserService extends IService<User> {
   
    List<User> queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance);
}
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Override
    public List<User> queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance) {
        //1.构造查询条件 like eq gt lt  
        return lambdaQuery()
                .like(name != null, User::getUsername, name)
                .eq(status != null, User::getStatus, status)
                .gt(minBalance != null, User::getBalance, minBalance)
                .lt(maxBalance != null, User::getBalance, maxBalance)
                .list();//2.查询一群list,一个one
    }
}

IService的Lambda更新

 

@Api(tags = "用户管理接口")
@RequestMapping("/users")
@RestController
@RequiredArgsConstructor
public class UserController {

    //@Autowired注入spring不推荐,而是推荐用注入函数来注入Service 可以用@RequiredArgsConstructor注解来自动调用函数注入Service
    private final IUserService userService;

    @ApiOperation("扣减用户余额接口")
    @PutMapping("/{id}/deduction/{money}")
    public void deductMoneyById(@ApiParam("用户id") @PathVariable("id") Long id,
                                @ApiParam("扣减的金额") @PathVariable("money") Integer money) {
        userService.deductMoneyById(id);
    }
}
public interface IUserService extends IService<User> {
    void deductBalanceById(Long id,Integer money);
}

如下用Lambda简化Impl中的方法。 

public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Override
    public void deductBalanceById(Long id, Integer money) {
        //1.查询用户
        User user=getById(id);     //继承了IService,故不用注入IUserService,可以直接调用mp方法获取用户
        //2.校验用户状态
        if(user==null || user.getStatus()==2){
            throw new RuntimeException("用户状态异常");
        }
        //3.校验余额是否充足
        if(user.getBalance()< money){
            throw new RuntimeException("用户余额不足");
        }
        // 4.扣减余额 update tb_user set balance =balance-?
        int remainBalance = user.getBalance() - money;//当前剩下余额
        lambdaUpdate()
                .set(User::getBalance,remainBalance)//设置余额
                .set(remainBalance == 0,User::getStatus,2) //当余额为0时,将用户状态置为2,表示用户账号冻结
                .eq(User::getId,id)//类似where id = ?
                .eq(User::getBalance,user.getBalance())//加一个前提条件,判断用户Balance等于查到的Balance,防止多线程同步问题(乐观锁)
                .update();//lambdaUpdate后面一定要跟一个update,这样才能真正执行sql语句
    }
}

总结:

普通的根据id的增删改查,建议直接使用IService提供的基础方法,比如 getById,listByIds,removeById等传统方法。如果使用复杂方法的查询建议使用Lambda方法查询,这样可以直接在Impl中构建,还可以用list查询多个,one查一个,page做分页,count做统计,功能强大。

 

5.IService的批量新增

最优方法:开启rewriteBatchedStatements=true参数

MybatisPlus的批处理:

@Test
void testSaveBatch() {
    // 准备10万条数据
    List<User> list = new ArrayList<>(1000);
    long b = System.currentTimeMillis();
    for (int i = 1; i <= 100000; i++) {
        list.add(buildUser(i));
        // 每1000条批量插入一次,网络请求次数减少,效率更高
        if (i % 1000 == 0) {
            userService.saveBatch(list);
            list.clear();
        }
    }
    long e = System.currentTimeMillis();
    System.out.println("耗时:" + (e - b));
}

修改项目中的application.yml文件,在jdbc的url后面添加参数&rewriteBatchedStatements=true:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root

这样批量新增的时间耗时最小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值