mybatis-plus自定义业务实现方式
作者:改了一个昵称
本文介绍了使用MyBatis-Plus(简称MP)进行数据库操作的实现步骤,包括创建实体类、Mapper接口和XML文件、Service接口和实现类,以及测试类,重点强调了业务层参数校验、事务管理以及复杂SQL的处理方式
结构
src/main/java/com/example/demo/ ├── DemoApplication.java // 启动类 ├── entity/User.java // 实体类 ├── mapper/UserMapper.java // Mapper 接口(含自定义SQL) ├── service/IUserService.java // Service 接口(自定义方法声明) └── service/impl/UserServiceImpl.java // Service 实现类(自定义方法实现) src/main/resources/ ├── application.yml // 配置文件 └── mapper/UserMapper.xml // 自定义SQL的XML文件(如需) src/test/java/com/example/demo/ └── UserServiceTest.java // 测试类
实体类 User
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("t_user") // 对应数据库表名
public class User {
@TableId(type = IdType.AUTO)
private Long id; // 主键自增
private String username; // 用户名
private String email; // 邮箱
private Integer age; // 年龄
private Integer status; // 状态:1-正常 0-禁用
}
Mapper 接口(UserMapper.java)
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface UserMapper extends BaseMapper<User> {
" 自定义SQL:根据年龄范围查询(也可通过Wrapper实现,这里演示XML方式) "
List<User> selectByAgeRange(@Param("minAge") Integer minAge, @Param("maxAge") Integer maxAge);
" 自定义SQL:统计不同年龄段的用户数量 "
List<Map<String, Object>> countUserByAgeGroup();
}
Mapper XML 文件(UserMapper.xml)
在 resources/mapper 下创建,存放自定义SQL:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<!-- 对应 selectByAgeRange 方法 -->
<select id="selectByAgeRange" resultType="com.example.demo.entity.User">
SELECT id, username, email, age, status
FROM t_user
WHERE age BETWEEN #{minAge} AND #{maxAge}
</select>
<!-- 对应 countUserByAgeGroup 方法 -->
<select id="countUserByAgeGroup" resultType="java.util.Map">
SELECT
CASE
WHEN age < 18 THEN '未成年'
WHEN age BETWEEN 18 AND 30 THEN '青年'
WHEN age BETWEEN 31 AND 50 THEN '中年'
ELSE '老年'
END AS age_group,
COUNT(*) AS user_count
FROM t_user
GROUP BY age_group
</select>
</mapper>
Service 接口(IUserService.java)
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.entity.User;
import java.util.List;
import java.util.Map;
public interface IUserService extends IService<User> {
"示例1:根据年龄范围查询用户(调用Mapper自定义SQL)"
List<User> getUserByAgeRange(Integer minAge, Integer maxAge);
"示例2:批量插入用户(基于MP的saveBatch扩展)"
int batchInsertUsers(List<User> userList);
"示例3:根据用户名模糊查询并按年龄降序排序(纯MP Wrapper实现)"
List<User> listUsersByUsernameLike(String usernameKeyword);
"示例4:统计不同年龄段的用户数量(调用Mapper自定义SQL)"
Map<String, Long> countUserByAgeGroup();
"示例5:逻辑删除+状态更新(业务组合操作)"
boolean disableUserById(Long userId);
}
Service 实现类(UserServiceImpl.java)
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.IUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
"示例1:调用Mapper自定义SQL实现年龄范围查询"
@Override
public List<User> getUserByAgeRange(Integer minAge, Integer maxAge) {
// 非空校验(业务层必备)
if (minAge == null || maxAge == null || minAge > maxAge) {
throw new IllegalArgumentException("年龄范围参数不合法");
}
return baseMapper.selectByAgeRange(minAge, maxAge);
}
"示例2:批量插入(扩展MP的saveBatch,增加批次控制和返回值)"
@Override
@Transactional(rollbackFor = Exception.class) // 事务保证
public int batchInsertUsers(List<User> userList) {
if (userList == null || userList.isEmpty()) {
return 0;
}
// MP的saveBatch默认批次是1000,这里自定义批次大小为500
boolean success = saveBatch(userList, 500);
return success ? userList.size() : 0;
}
"示例3:纯Wrapper实现模糊查询+排序"
@Override
public List<User> listUsersByUsernameLike(String usernameKeyword) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
.like(usernameKeyword != null, User::getUsername, usernameKeyword) // 非空才拼接条件
.orderByDesc(User::getAge); // 按年龄降序
return list(wrapper); // 调用IService的默认方法
}
"示例4:统计年龄段数量(处理Mapper返回的Map)"
@Override
public Map<String, Long> countUserByAgeGroup() {
List<Map<String, Object>> resultList = baseMapper.countUserByAgeGroup();
Map<String, Long> ageGroupMap = new HashMap<>();
for (Map<String, Object> map : resultList) {
String ageGroup = (String) map.get("age_group");
Long userCount = (Long) map.get("user_count");
ageGroupMap.put(ageGroup, userCount);
}
return ageGroupMap;
}
"示例5:组合业务操作(逻辑删除+状态更新)"
@Override
@Transactional(rollbackFor = Exception.class)
public boolean disableUserById(Long userId) {
// 1. 查询用户是否存在
User user = getById(userId);
if (user == null) {
return false;
}
// 2. 更新状态为禁用(0)
user.setStatus(0);
return updateById(user);
}
}
测试类(UserServiceTest.java)
import com.example.demo.DemoApplication;
import com.example.demo.entity.User;
import com.example.demo.service.IUserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@SpringBootTest(classes = DemoApplication.class)
public class UserServiceTest {
@Autowired
private IUserService userService;
// 测试示例1:年龄范围查询
@Test
public void testUserByAgeRange() {
List<User> userList = userService.getUserByAgeRange(18, 30);
System.out.println("18-30岁用户:" + userList);
}
// 测试示例2:批量插入
@Test
public void testBatchInsert() {
List<User> userList = new ArrayList<>();
User u1 = new User();
u1.setUsername("张三");
u1.setEmail("zhangsan@test.com");
u1.setAge(25);
u1.setStatus(1);
User u2 = new User();
u2.setUsername("李四");
u2.setEmail("lisi@test.com");
u2.setAge(28);
u2.setStatus(1);
userList.add(u1);
userList.add(u2);
int count = userService.batchInsertUsers(userList);
System.out.println("批量插入成功数量:" + count);
}
// 测试示例3:模糊查询+排序
@Test
public void testListByUsernameLike() {
List<User> userList = userService.listUsersByUsernameLike("张");
System.out.println("用户名含'张'的用户(按年龄降序):" + userList);
}
// 测试示例4:统计年龄段
@Test
public void testCountAgeGroup() {
Map<String, Long> ageGroupMap = userService.countUserByAgeGroup();
System.out.println("年龄段统计:" + ageGroupMap);
}
// 测试示例5:禁用用户
@Test
public void testDisableUser() {
boolean success = userService.disableUserById(1L);
System.out.println("禁用用户是否成功:" + success);
}
}
数据库
CREATE TABLE `t_user` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', `username` varchar(50) NOT NULL COMMENT '用户名', `email` varchar(100) DEFAULT NULL COMMENT '邮箱', `age` int DEFAULT NULL COMMENT '年龄', `status` int DEFAULT 1 COMMENT '状态:1-正常 0-禁用', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
总结
自定义Service方法的核心:
继承 IService/ServiceImpl 后,可通过 baseMapper 调用自定义Mapper方法,或通过 Wrapper 直接使用MP的内置方法。
关键规范:
- 业务层必须做参数校验,避免非法输入;
- 批量操作/组合操作需加
@Transactional保证事务; - 复杂SQL建议写在XML中,简单条件用
Wrapper更简洁。
扩展思路:
自定义方法可覆盖“查询封装、批量操作、业务组合、数据统计”等场景,核心是复用MP的基础能力,同时适配业务需求。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
