mybatis-plus自定义业务实现方式

 更新时间:2026年03月17日 10:58:06   作者:改了一个昵称  
本文介绍了使用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的基础能力,同时适配业务需求。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java编程之如何通过JSP实现头像自定义上传

    Java编程之如何通过JSP实现头像自定义上传

    之前做这个头像上传功能还是花了好多时间的,今天我将我的代码分享给大家,下面这篇文章主要给大家介绍了关于Java编程之如何通过JSP实现头像自定义上传的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • 解决java maven项目找不到jconsole-1.8.0.jar和tools-1.8.0.jar包问题

    解决java maven项目找不到jconsole-1.8.0.jar和tools-1.8.0.jar包问题

    这篇文章主要介绍了解决java maven项目找不到jconsole-1.8.0.jar和tools-1.8.0.jar包问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • SpringBoot使用flyway初始化数据库

    SpringBoot使用flyway初始化数据库

    这篇文章主要介绍了SpringBoot如何使用flyway初始化数据库,帮助大家更好的理解和学习使用SpringBoot框架,感兴趣的朋友可以了解下
    2021-03-03
  • Java中的BufferedInputStream与BufferedOutputStream使用示例

    Java中的BufferedInputStream与BufferedOutputStream使用示例

    BufferedInputStream和BufferedOutputStream分别继承于FilterInputStream和FilterOutputStream,代表着缓冲区的输入输出,这里我们就来看一下Java中的BufferedInputStream与BufferedOutputStream使用示例:
    2016-06-06
  • Java中的volatile实现机制详细解析

    Java中的volatile实现机制详细解析

    这篇文章主要介绍了Java中的volatile实现机制详细解析,本文的主要内容就在于要理解volatile的缓存的一致性协议导致的共享变量可见性,以及volatile在解析成为汇编语言的时候对变量加锁两块理论内容,需要的朋友可以参考下
    2024-01-01
  • Spring项目集成RabbitMQ及自动创建队列

    Spring项目集成RabbitMQ及自动创建队列

    这篇文章主要介绍了Spring项目集成RabbitMQ及自动创建队列,本文内容分别在Spring(V5.2.6)和Spring Boot(V2.5.14)两个项目中经过了验证,需要的朋友可以参考下
    2024-02-02
  • Spring Boot 入门之消息中间件的使用

    Spring Boot 入门之消息中间件的使用

    本篇文章主要介绍了Spring Boot 入门之消息中间件的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • SpringBoot后台实现文件上传下载

    SpringBoot后台实现文件上传下载

    这篇文章主要为大家详细介绍了SpringBoot后台实现文件上传下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • Java基于JavaMail实现向QQ邮箱发送邮件

    Java基于JavaMail实现向QQ邮箱发送邮件

    这篇文章主要为大家详细介绍了Java基于JavaMail实现向QQ邮箱发送邮件的相关资料,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-01-01
  • JavaWeb三大组件之Filter过滤器详解

    JavaWeb三大组件之Filter过滤器详解

    这篇文章主要介绍了JavaWeb三大组件之Filter过滤器详解,过滤器Filter是Java Web应用中的一种组件,它在请求到达Servlet或JSP之前或者响应送回客户端之前,对请求和响应进行预处理和后处理操作,需要的朋友可以参考下
    2023-10-10

最新评论