三 常用功能
3 Service接口实现crud
mp提供Service接口和该Service接口的实现类,内含多种crud方法,自定义Service接口与实现类继承二者即可使用
// IUserService
public interface IUserService extends IService<User> {
}
// IUserServiceImpl
@Service
// 继承参数中的泛型表示所需要用到的mapper与操作实体
public class IUserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{
}
生成测试类
// 简单操作
@SpringBootTest
class IUserServiceTest {
@Autowired
private IUserService userService;
@Test
void testSaveUser(){
User user = new User();
user.setId(7);
user.setUsername("black");
user.setIsPlayer(true);
user.setOrder(3);
userService.save(user);
}
@Test
void testQuery(){
List<Long> ids = Arrays.asList(1L, 2L, 3L);
List<User> users = userService.listByIds(ids);
users.forEach(System.out::println);
}
}
4 基于Restful风格实现接口
① 引入依赖
<!--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>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
② 引入配置文件 – application.yaml
knife4j:
enable: true
openapi:
title: 用户管理接口文档
description: "用户管理接口文档"
email: yellow@itdemo.cn
concat: 大黄
url: https://www.itdemo.com
version: v1.0.0
group:
default:
group-name: default
api-rule: package
api-rule-resources:
- com.tj.mp.demo.controller
③ 编写POVO实体类
@Data
@ApiModel(description = "用户表单实体")
// Dto通过封装数据来简化数据传递过程,减少系统耦合,提高性能和可维护性。
@TableName("tb_user")
public class UserFromDTO {
@ApiModelProperty("id")
private Integer id;
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("是否玩家")
private Boolean isPlayer;
@ApiModelProperty("测关键字")
private Integer order;
@ApiModelProperty("地址")
private String address;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
// PO 是与数据库表结构直接映射的对象,用于表示数据库中的记录。
@TableName("tb_user")
public class User {
@TableId(value = "id",type = IdType.AUTO)
private Integer id;
@TableField(value = "username")
private String username;
@TableField("is_player")
private Boolean isPlayer;
@TableField("`order`")
private Integer order;
@TableField(exist = false)
private String address;
}
@Data
@ApiModel(description = "用户VO实体")
// VO 是为前端视图(如网页、移动端界面)设计的对象,用于展示数据。
@TableName("tb_user")
public class UserVo {
@ApiModelProperty("id")
private Integer id;
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("是否玩家")
private Boolean isPlayer;
@ApiModelProperty("测关键字")
private Integer order;
@ApiModelProperty("地址")
private String address;
}
④ Controller – UserController
// Swagger 注解
@Api(tags = "用户管理接口")
@RequestMapping("/users")
@RestController
@CrossOrigin
// 必备的构造函数,对一开始需要初始化的进行构造,lombok注解
@RequiredArgsConstructor
public class UserController {
//spring推荐使用构造函数注入service
// 加final表示常量,在初始化的过程中,进行注入
private final IUserService userService;
// @Autowired
// UserMapper userMapper;
// Restful风格表单实体以Json方式提交,通过RequestBody进行接收
@ApiOperation("新增用户接口")
@PostMapping
public void saveUser(@RequestBody UserFromDTO userFromDTO){
// 1.DTO拷贝至PO
User user = BeanUtil.copyProperties(userFromDTO, User.class);
// 2.新增
userService.save(user);
}
@ApiOperation("删除用户接口")
@DeleteMapping("{id}")
public void deleteUserById(@ApiParam("用户id")@PathVariable("id")Long id){
userService.removeById(id);
}
@ApiOperation("通过id查询用户接口")
@GetMapping("{id}")
public UserVo queryUserById(@ApiParam("用户id")@PathVariable("id")Long id){
// 1.查询用户PO
User user = userService.getById(id);
// 2.PO拷贝到VO
return BeanUtil.copyProperties(user,UserVo.class);
}
@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
return BeanUtil.copyToList(users,UserVo.class);
}
@ApiOperation("扣除用户资源")
@PutMapping("{id}/deduction/{order}")
public void deductOrder(
@ApiParam("用户id")@PathVariable("id")Long id,
@ApiParam("扣减的资源")@PathVariable("order")Long order){
userService.deductOrder(id,order);
}
}
⑤ Service – IUserService ,IUserServiceImpl
public interface IUserService extends IService<User> {
void deductOrder(Long id, Long order);
}
@Service
// 继承参数中的泛型表示所需要用到的mapper与操作实体
public class IUserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{
@Override
public void deductOrder(Long id, Long order) {
// 1.查询用户 本类方法直接用即可
User user = getById(id);
// 2.检验资源是否充足 反向思维防止嵌套
if (user.getOrder() < order){
throw new RuntimeException("用户无资源");
}
// 3.减去资源
baseMapper.deductOrder(id,order);
}
}
⑥ mapper – UserMapper
// 继承后底层已封装好crud
public interface UserMapper extends BaseMapper<User> {
void updateOrderByIds(@Param("ew")QueryWrapper<User> wrapper, @Param("amount")int amount);
@Update("update tb_user set `order` = `order` - #{order} where id=#{id}")
void deductOrder(@Param("id")Long id, @Param("order")Long order);
}
⑦ 启动demo进行测试(alt+8),新增,查询,扣减,删除
http://localhost:8081/doc.html#/home
5 IService的Lambda查询更新
① 新增实体类 – UserQuery
// 接收参数
@Data
@ApiModel(description = "用户查询实体")
public class UserQuery {
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("是否玩家")
private Boolean isPlayer;
@ApiModelProperty("资源最大值")
private Integer maxOrder;
@ApiModelProperty("资源最小值")
private Integer minOrder;
}
② 新增 UserController方法
@ApiOperation("通过复杂条件查询用户接口")
@GetMapping("/list")
public List<UserVo> queryUsers(UserQuery query){
// 1.查询用户PO
List<User> users = userService.queryUsers(
query.getUsername(),query.getIsPlayer(),query.getMaxOrder(),query.getMinOrder());
// 2.PO拷贝到VO
return BeanUtil.copyToList(users,UserVo.class);
}
③ 新增 IUserService,IUserServiceImpl方法
List<User> queryUsers(String username, Boolean isPlayer, Integer maxOrder, Integer minOrder);
@Override
public List<User> queryUsers(String username, Boolean isPlayer, Integer maxOrder, Integer minOrder) {
return lambdaQuery()
.like(username != null, User::getUsername, username)
.eq(isPlayer != null, User::getIsPlayer, isPlayer)
.lt(maxOrder != null, User::getOrder, maxOrder)
.gt(minOrder != null, User::getOrder, minOrder)
.list();// 含多种返回类型可供选择
}
④ 测试
⑤ Lambda方式更新:对IUserServiceImpl
中的查询方法进行修改即可
@Override
public void deductOrder(Long id, Long order) {
// 1.查询用户 本类方法直接用即可
User user = getById(id);
// 2.检验资源是否充足 反向思维防止嵌套
if (user.getOrder() < order){
throw new RuntimeException("用户无资源");
}
// 3.减去资源
Long remainOrder=user.getOrder()-order;
// 4.构建条件并执行
lambdaUpdate()
.set(User::getOrder,remainOrder)// 赋值
.set(remainOrder<0,User::getIsPlayer,false)//无资源则取消玩家身份
.eq(User::getId,id)// 根据id查询
// 用户资源需等于刚才查询到的资源
.eq(User::getOrder,user.getOrder())// 乐观锁 先比较再更新
.update();// 执行
}
⑥ 测试
6 IService的批量新增
此处需要对yaml中的mysql批处理方式进行设置,rewriteBatchedStatements=true
设置后会将多条sql语句合并为一个批量请求,减少网络传输次数,降低延迟。相对于for循环插入与默认的mp批处理(将编译的1000行一次性提交,但还是1条sql执行1行数据)设置好参数后,速度会有很大提升。需注意每次批处理new出的对象是占内存的,向数据库传递的数据包也是有大小的,所以一次批处理也不能提交过多数据。
spring:
application:
name: demo
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mp_test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&rewriteBatchedStatements=true
username: root
password: root
// 未设置
INSERT INTO tb_user (username, is_player, `order`)
VALUES ('exampleUsername1', true, 1);
INSERT INTO tb_user (username, is_player, `order`)
VALUES ('exampleUsername2', true, 2);
...
// 已设置
INSERT INTO tb_user (username, is_player, `order`)
VALUES
('exampleUsername1', true, 1),
('exampleUsername2', true, 2)
...;
普通for循环测试
private User buildUser(int i) {
User user = new User();
user.setUsername("user_" + i);
user.setOrder(i);
user.setIsPlayer(true);
return user;
}
@Test
void testSaveOneByOne() {
long b = System.currentTimeMillis();
for (int i = 1; i <= 100000; i++) {
userService.save(buildUser(i));
}
long e = System.currentTimeMillis();
System.out.println("耗时:"+(e - b));
}
mp批处理插入测试(开启参数代码不需变化)
@Test
void testSaveBatch() {
// 我们每次批量插入1000条,插入100次即10万条数据
// 1. 准备一个容量为1000的集合
List<User> list = new ArrayList<>(1000);
long b = System.currentTimeMillis();
for (int i = 1; i <= 100000; i++) {
// 2. 添加一个user
list.add(buildUser(i));
// 3. 每1000条批量插入一次
if (i % 1000 == 0) {
// 底层预编译方案,将语句打包后再提交
userService.saveBatch(list);
// 4. 清空集合,准备下一批数据
list.clear();
}
}
long e = System.currentTimeMillis();
System.out.println("耗时:" + (e - b));
}