SpringBoot + MyBatis注解式实现Dept表完整CRUD(含分页/模糊/批量操作)

在SpringBoot项目开发中,MyBatis注解式开发无需编写XML映射文件,能极大简化持久层代码,提升开发效率。本文将以部门表(dept)为案例,完整实现基本增删改查、分页查询、模糊查询、批量新增、批量删除及局部修改功能,全程仅编写实体类、Mapper接口和测试类。

一、环境准备

核心技术:SpringBoot 2.7.x、MyBatis 3.x、MySQL 8.x、PageHelper(分页插件)

pom.xml文件配置

    <dependencies>
        <!--springMVC的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--mybatis的依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>3.0.5</version>
            <scope>test</scope>
        </dependency>
        <!--myBatis分页-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.6</version>
        </dependency>
        <!--测试依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--springboot 热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--mysql 连接对象-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

1.2 数据库表设计

image

1.3 核心配置(application.properties)

spring.application.name=boot-demo-dept
spring.datasource.url=jdbc:mysql://localhost:3306/employee?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

二、核心代码实现

项目结构说明(按以下目录创建,无需额外配置):

image

2.1 实体类与查询对象

(1)部门实体类(Dept)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
    private Long deptno;
    private String dname;
    private String loc;
}
(2)查询对象(DeptQO)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeptQO {
    private Long deptno;
    private String dname;
    private String loc;
}

2.2 Mapper接口(DeptMapper)

核心接口,用MyBatis注解编写SQL,无需XML。通过@Mapper注解将接口注入IOC容器,SpringBoot自动创建实例。
接口中包含所有CRUD、分页、模糊、批量操作,整合Provider类处理复杂SQL(模糊查询、批量操作等):

package cn.wolfcode.mapper;

import cn.wolfcode.domain.Dept;
import cn.wolfcode.qo.DeptQO;
import org.apache.ibatis.annotations.*;
import org.springframework.util.StringUtils;

import java.util.List;

@Mapper
public interface DeptMapper {


    @Select("select * from dept")
    @Results({
            @Result(property = "deptno",column = "deptno" ,id = true),
            @Result(property = "dname",column = "dname"),
            @Result(property = "loc",column = "loc")
    })
    List<Dept> selectAll();

    @SelectProvider(type = DeptProvider.class,method = "selectByCondition")
    @Results({
            @Result(property = "deptno",column = "deptno" ,id = true),
            @Result(property = "dname",column = "dname"),
            @Result(property = "loc",column = "loc")
    })
    List<Dept> selectByCondition(DeptQO dept);

    @Select("select * from dept where deptno=#{id}")
    @Results({
            @Result(property = "deptno",column = "deptno",id = true),
            @Result(property = "dname",column = "dname"),
            @Result(property = "loc",column = "loc")
    })
    Dept selectById(Long i);

    @Insert("insert into dept(dname,loc) values (#{dname},#{loc})")
    @Options(useGeneratedKeys = true,keyProperty = "deptno")
    int insert(Dept dept);

    @InsertProvider(type = DeptProvider.class,method = "inserts")
    @Options(useGeneratedKeys = true,keyProperty = "deptno")
    int inserts(List<Dept> dept);

    @Delete("delete from dept where deptno=#{deptno}")
    int delete(Long i);

    @DeleteProvider(type = DeptProvider.class,method="deleteByIds")
    int deleteByIds(Long[] i);

    @Update("update dept set dname=#{dname},loc=#{loc} where deptno=#{deptno}")
    int update(Dept dept);

    @UpdateProvider(type = DeptProvider.class,method = "updatePatch")
    int updatePatch(Dept dept);


    class  DeptProvider{
        public String selectByCondition(DeptQO dept){
            StringBuffer sql=new StringBuffer("select * from dept where 1=1 ");
            if(!StringUtils.isEmpty(dept.getDname())) {
                sql.append(" and dname like concat('%',#{dname},'%')");
            }
            if(!StringUtils.isEmpty(dept.getLoc()))
                sql.append(" and loc like concat('%',#{loc},'%')");

            //sql.substring(0,sql.length()-1);

            return sql.toString();
        }

        public String inserts(List<Dept> dept){
            StringBuffer sql = new StringBuffer("insert into dept(dname,loc) values ");
            for(int i=0;i<dept.size();i++){
                sql.append("(#{dept["+i+"].dname},#{dept["+i+"].loc}),");
            }
            String substring = sql.substring(0, sql.length() - 1);
            return substring;
        }

        public String deleteByIds(Long[] i){
            StringBuffer sql = new StringBuffer("delete from dept where deptno in(");
            for (Long id:i){
                sql.append(id).append(",");

            }
            String substring = sql.substring(0, sql.length() - 1);
            substring=substring+")";
            return substring;
        }

        public String updatePatch(Dept dept){
            StringBuffer sql = new StringBuffer("update dept set");
            if(!StringUtils.isEmpty(dept.getDname())){
                sql.append(" dname=#{dname},");
            }
            if(!StringUtils.isEmpty(dept.getLoc())){
                sql.append(" loc=#{loc},");
            }

            String substring = sql.substring(0, sql.length() - 1);
            substring+=" where deptno=#{deptno}";
            return substring;
        }
    }
}

2.3 测试类编写

创建测试类,通过@Autowired注入DeptMapper实例,逐个测试所有功能。测试类放在src/test/java目录下,与主程序包结构一致。

@SpringBootTest
class BootDemoDeptApplicationTests {
    @Autowired
    private DeptMapper deptMapper;

    //查询全部
    @Test
    void selectAll() {
        List<Dept> deptList=deptMapper.selectAll();
        deptList.forEach(System.out::println);
    }
    //根据id查
    @Test
    void selectById() {
        Long i=140L;
        Dept dept=deptMapper.selectById(i);

        System.out.println(dept);
    }

    //模糊查询
    @Test
    void selectByCondition() {
        DeptQO dept=new DeptQO();
        dept.setDname("A");
        dept.setLoc("A");
        List<Dept> deptList=deptMapper.selectByCondition(dept);
        System.out.println(deptList);
        deptList.forEach(System.out::println);
    }

    //分页查询
    @Test
    void selectByConditionPage() {
        DeptQO dept=new DeptQO();
        PageHelper.startPage(1,3);
        List<Dept> deptList=deptMapper.selectByCondition(dept);

        PageInfo<Dept> deptPageInfo = new PageInfo<>(deptList);
        deptPageInfo.getList().stream().forEach(System.out::println);
    }

    //分页查询
    @Test
    void selectByConditionPage2() {
        PageHelper.startPage(2,3);
        List<Dept> deptList = deptMapper.selectAll();
        PageInfo<Dept> deptPageInfo = new PageInfo<>(deptList);
        deptPageInfo.getList().stream().forEach(System.out::println);
    }



    //增加
    @Test
    void insert(){
        Dept dept = new Dept(null, "OTO", "ULC");
        int i=deptMapper.insert(dept);
        System.out.println(i>0?"添加成功":"添加失败");
    }
    //批量增加
    @Test
    void inserts(){
        List<Dept> dept = List.of(
                new Dept(null, "O.O", "ULC"),
                new Dept(null,"O.o","URL")
        );
        int i=deptMapper.inserts(dept);
        System.out.println(i>0?"添加成功":"添加失败");
    }

    //删除
    @Test
    void delete(){
        Long i=181L;
        int m=deptMapper.delete(i);
        System.out.println(m>0?"删除成功":"删除失败");
    }

    //批量删除
    @Test
    void deleteByIds(){
        Long[] i={182L,183L,184L};
        int m=deptMapper.deleteByIds(i);
        System.out.println(m>0?"删除成功":"删除失败");
    }

    //全量修改
    @Test
    void update(){
        Dept dept = new Dept(120L, "产品部", "UK");
        int m=deptMapper.update(dept);
        System.out.println(m>0?"修改成功":"修改失败");
    }

    //局部修改1
    @Test
    void updatePatch1(){
        Dept dept = new Dept(120L, null, "University");
        int m=deptMapper.updatePatch(dept);
        System.out.println(m>0?"修改成功":"修改失败");
    }

    //局部修改2
    @Test
    void updatePatch2(){
        Dept deptData = new Dept(120L, null, "UK");

        Dept dept = deptMapper.selectById(120L);
        if(!StringUtils.isEmpty(deptData.getDname())){
            dept.setDname(deptData.getDname());
        }
        if(!StringUtils.isEmpty(deptData.getLoc())){
            dept.setLoc(deptData.getLoc());
        }

        int m=deptMapper.update(dept);
        System.out.println(m>0?"修改成功":"修改失败");
    }
}

三、关键知识点解析

3.1 MyBatis核心注解说明

  • @Mapper:将接口注入IOC容器,SpringBoot自动创建代理实现类,无需手动配置。

  • @Select/@Insert/@Delete/@Update:简化单条SQL操作,直接编写SQL语句。

  • @Results/@Result:用于字段映射(当实体类字段与数据库字段不一致时使用,本文字段一致可省略,但建议保留规范)。

  • @SelectProvider/@InsertProvider等:用于复杂SQL生成(如动态条件、批量操作),指定Provider类和方法,灵活拼接SQL。

  • @Options:配置主键自增,将数据库生成的自增主键赋值给实体类对应的字段。

3.2 PageHelper分页原理

PageHelper是MyBatis的分页插件,核心原理是动态代理+SQL拼接

PageHelper.startPage()必须在查询语句之前调用,且仅对紧接着的第一个查询生效。

四、总结与扩展

4.1 总结

本文通过SpringBoot + MyBatis注解式开发,完整实现了部门表的所有核心持久层操作,核心优势:

  • 无需编写XML映射文件,代码简洁,开发效率高。

  • 通过Provider类灵活处理复杂SQL,兼顾灵活性和规范性。

  • 整合PageHelper实现分页,简化分页逻辑。

posted @ 2026-01-31 15:15  Jennifer_F  阅读(35)  评论(0)    收藏  举报