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 实现最小二叉树堆排序的实例

    java 实现最小二叉树堆排序的实例

    这篇文章主要介绍了java 实现最小二叉树堆排序的实例的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-09-09
  • Java中的@SneakyThrows注解用法详解

    Java中的@SneakyThrows注解用法详解

    这篇文章主要介绍了Java中的@SneakyThrows注解用法的相关资料,Lombok的@SneakyThrows注解简化了Java方法中的异常处理,使得代码更加简洁和易读,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-04-04
  • Java动态代理静态代理实例分析

    Java动态代理静态代理实例分析

    这篇文章主要介绍了Java动态代理静态代理实例分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • MyBatis详解如何实现Dao层接口

    MyBatis详解如何实现Dao层接口

    MyBatis允许只声明一个dao接口,而无需写dao实现类的方式实现数据库操作。前提是必须保证Mapper文件中的<mapper>标签的namespace属性值必须要和dao接口的类路径一致,MyBatis容器会自动通过动态代理生成接口的实现类
    2022-04-04
  • SpringBoot多种场景传参模式

    SpringBoot多种场景传参模式

    传参是非常常见的,本文主要介绍了SpringBoot多种场景传参模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • IntelliJ IDEA将导入的项目转成maven项目

    IntelliJ IDEA将导入的项目转成maven项目

    这篇文章主要介绍了IntelliJ IDEA将导入的项目转成maven项目,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • java泛型学习示例

    java泛型学习示例

    Java泛型(Generics)是JDK5开始引入的一个新特性,允许在定义类和接口的时候使用类型参数(Type Parameter)。下面是学习泛型的示例
    2014-04-04
  • 基于Java注解(Annotation)的自定义注解入门介绍

    基于Java注解(Annotation)的自定义注解入门介绍

    要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法
    2013-04-04
  • java8新特性-lambda表达式入门学习心得

    java8新特性-lambda表达式入门学习心得

    这篇文章主要介绍了java8新特性-lambda表达式入门学习心得,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • 浅谈SpringBoot2.3 新特配置文件属性跟踪

    浅谈SpringBoot2.3 新特配置文件属性跟踪

    这篇文章主要介绍了浅谈SpringBoot2.3 新特配置文件属性跟踪,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06

最新评论