Spring Boot + MyBatis Plus 实战:企业级应用开发最佳实践指南

Helen846
Helen846 2026-02-05T10:03:09+08:00
0 0 1

引言

在现代Java企业级应用开发中,Spring Boot与MyBatis Plus的组合已经成为主流技术栈之一。Spring Boot以其"约定优于配置"的理念简化了Spring应用的初始搭建和开发过程,而MyBatis Plus则通过其强大的功能扩展,极大地提升了数据库操作的效率和便捷性。本文将深入探讨如何在企业级项目中高效地集成和使用这两个框架,涵盖从基础配置到高级特性的完整实践指南。

一、环境准备与基础配置

1.1 项目结构搭建

首先,我们需要创建一个基于Spring Boot的项目,并引入MyBatis Plus相关依赖。推荐使用Spring Initializr来快速生成项目骨架:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.1</version>
    </dependency>
    
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

1.2 数据库配置

application.yml中配置数据库连接信息:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/enterprise_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
    
mybatis-plus:
  configuration:
    # 开启下划线转驼峰
    map-underscore-to-camel-case: true
    # 日志配置
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      # 主键策略
      id-type: auto

1.3 核心配置类

创建MyBatis Plus的配置类来启用相关功能:

@Configuration
public class MyBatisPlusConfig {
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

二、代码生成器实战

2.1 代码生成器基础使用

MyBatis Plus提供了强大的代码生成器功能,能够根据数据库表结构自动生成Mapper、Service、Controller等代码:

public class CodeGenerator {
    
    public static void main(String[] args) {
        // 全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
        globalConfig.setAuthor("developer");
        globalConfig.setOpen(false);
        globalConfig.setSwagger2(true);
        
        // 数据源配置
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/enterprise_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8");
        dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSourceConfig.setUsername("root");
        dataSourceConfig.setPassword("password");
        
        // 包配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setParent("com.example.enterprise");
        packageConfig.setModuleName("user");
        packageConfig.setEntity("entity");
        packageConfig.setMapper("mapper");
        packageConfig.setService("service");
        packageConfig.setServiceImpl("service.impl");
        packageConfig.setController("controller");
        
        // 策略配置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setEntityLombokModel(true);
        strategyConfig.setRestControllerStyle(true);
        strategyConfig.setInclude("user", "department"); // 指定生成的表
        
        AutoGenerator autoGenerator = new AutoGenerator();
        autoGenerator.setGlobalConfig(globalConfig);
        autoGenerator.setDataSource(dataSourceConfig);
        autoGenerator.setPackageInfo(packageConfig);
        autoGenerator.setStrategy(strategyConfig);
        
        autoGenerator.execute();
    }
}

2.2 自定义代码生成规则

在实际项目中,我们可能需要更复杂的代码生成逻辑:

public class CustomCodeGenerator {
    
    public static void generateWithCustomRules() {
        // 基础配置保持不变
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
        globalConfig.setAuthor("developer");
        globalConfig.setOpen(false);
        
        // 自定义模板配置
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setXml(null); // 不生成XML文件
        
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setEntityLombokModel(true);
        strategyConfig.setRestControllerStyle(true);
        
        // 配置字段注解
        strategyConfig.setTableFillList(Arrays.asList(
            new TableFill("create_time", FieldFill.INSERT),
            new TableFill("update_time", FieldFill.INSERT_UPDATE)
        ));
        
        AutoGenerator autoGenerator = new AutoGenerator();
        autoGenerator.setGlobalConfig(globalConfig);
        autoGenerator.setDataSource(getDataSourceConfig());
        autoGenerator.setPackageInfo(getPackageConfig());
        autoGenerator.setStrategy(strategyConfig);
        autoGenerator.setTemplate(templateConfig);
        
        autoGenerator.execute();
    }
    
    private static DataSourceConfig getDataSourceConfig() {
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        // ... 数据源配置
        return dataSourceConfig;
    }
    
    private static PackageConfig getPackageConfig() {
        PackageConfig packageConfig = new PackageConfig();
        // ... 包配置
        return packageConfig;
    }
}

三、实体类设计与注解使用

3.1 基础实体类定义

@TableName("user")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    
    @TableField("user_name")
    private String userName;
    
    private String email;
    
    private Integer age;
    
    @TableField("create_time")
    private LocalDateTime createTime;
    
    @TableField("update_time")
    private LocalDateTime updateTime;
    
    @TableLogic
    @TableField("deleted")
    private Integer deleted;
}

3.2 高级注解使用

@TableName("department")
@Data
@EqualsAndHashCode(callSuper = true)
public class Department extends BaseEntity {
    
    /**
     * 部门名称
     */
    @TableField("dept_name")
    private String deptName;
    
    /**
     * 部门编码
     */
    @TableField("dept_code")
    private String deptCode;
    
    /**
     * 父部门ID
     */
    @TableField("parent_id")
    private Long parentId;
    
    /**
     * 部门层级
     */
    @TableField("level")
    private Integer level;
    
    /**
     * 排序字段
     */
    @TableField("sort_order")
    private Integer sortOrder;
    
    /**
     * 状态:0-禁用,1-启用
     */
    private Integer status;
}

四、Mapper层开发最佳实践

4.1 基础Mapper接口

@Mapper
public interface UserMapper extends BaseMapper<User> {
    
    /**
     * 根据用户名查询用户
     */
    User selectByUsername(@Param("username") String username);
    
    /**
     * 批量删除用户
     */
    int deleteBatchIds(@Param("ids") List<Long> ids);
}

4.2 自定义Mapper方法

@Mapper
public interface DepartmentMapper extends BaseMapper<Department> {
    
    /**
     * 根据父ID查询子部门列表
     */
    List<Department> selectByParentId(@Param("parentId") Long parentId);
    
    /**
     * 查询部门及其子部门的树形结构
     */
    List<Department> selectDeptTree(@Param("parentId") Long parentId);
    
    /**
     * 统计部门下用户数量
     */
    int countUsersInDept(@Param("deptId") Long deptId);
}

4.3 动态SQL使用

@Mapper
public interface UserMapper extends BaseMapper<User> {
    
    /**
     * 复杂查询条件组合
     */
    List<User> selectUserByCondition(
        @Param("userName") String userName,
        @Param("email") String email,
        @Param("age") Integer age,
        @Param("startTime") LocalDateTime startTime,
        @Param("endTime") LocalDateTime endTime
    );
    
    /**
     * 使用XML方式编写复杂SQL
     */
    List<User> selectUserWithRole(@Param("userId") Long userId);
}

对应的XML文件:

<?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.enterprise.mapper.UserMapper">
    
    <select id="selectUserByCondition" resultType="com.example.enterprise.entity.User">
        SELECT * FROM user 
        <where>
            <if test="userName != null and userName != ''">
                AND user_name LIKE CONCAT('%', #{userName}, '%')
            </if>
            <if test="email != null and email != ''">
                AND email = #{email}
            </if>
            <if test="age != null">
                AND age = #{age}
            </if>
            <if test="startTime != null">
                AND create_time >= #{startTime}
            </if>
            <if test="endTime != null">
                AND create_time &lt;= #{endTime}
            </if>
        </where>
        ORDER BY create_time DESC
    </select>
    
    <select id="selectUserWithRole" resultType="com.example.enterprise.entity.User">
        SELECT u.*, r.role_name 
        FROM user u 
        LEFT JOIN user_role ur ON u.id = ur.user_id 
        LEFT JOIN role r ON ur.role_id = r.id 
        WHERE u.id = #{userId}
    </select>
</mapper>

五、Service层开发与事务管理

5.1 基础Service实现

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    public User getUserByUsername(String username) {
        return userMapper.selectByUsername(username);
    }
    
    @Override
    public boolean saveUser(User user) {
        return this.save(user);
    }
    
    @Override
    public boolean updateUser(User user) {
        return this.updateById(user);
    }
}

5.2 复杂业务逻辑处理

@Service
@Transactional(rollbackFor = Exception.class)
public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department> implements DepartmentService {
    
    @Autowired
    private DepartmentMapper departmentMapper;
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    public boolean createDepartment(Department department) {
        // 设置创建时间
        department.setCreateTime(LocalDateTime.now());
        department.setUpdateTime(LocalDateTime.now());
        
        return this.save(department);
    }
    
    @Override
    public boolean updateDepartment(Department department) {
        department.setUpdateTime(LocalDateTime.now());
        return this.updateById(department);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteDepartment(Long deptId) {
        // 检查部门下是否有用户
        int userCount = userMapper.countUsersInDept(deptId);
        if (userCount > 0) {
            throw new BusinessException("部门下存在用户,无法删除");
        }
        
        // 检查是否有子部门
        List<Department> children = departmentMapper.selectByParentId(deptId);
        if (!CollectionUtils.isEmpty(children)) {
            throw new BusinessException("部门下存在子部门,无法删除");
        }
        
        return this.removeById(deptId);
    }
    
    @Override
    public List<Department> getDeptTree(Long parentId) {
        return departmentMapper.selectDeptTree(parentId);
    }
}

5.3 事务管理最佳实践

@Service
public class UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private DepartmentMapper departmentMapper;
    
    /**
     * 用户注册事务处理
     */
    @Transactional(rollbackFor = Exception.class)
    public User registerUser(User user, Long deptId) {
        // 保存用户
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        userMapper.insert(user);
        
        // 更新部门用户统计
        Department department = departmentMapper.selectById(deptId);
        if (department != null) {
            department.setUpdateTime(LocalDateTime.now());
            departmentMapper.updateById(department);
        }
        
        return user;
    }
    
    /**
     * 批量操作事务管理
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteUsers(List<Long> userIds) {
        try {
            // 批量删除用户
            userMapper.deleteBatchIds(userIds);
            
            // 记录操作日志
            logOperation("批量删除用户", String.join(",", userIds.stream()
                .map(String::valueOf)
                .collect(Collectors.toList())));
            
            return true;
        } catch (Exception e) {
            log.error("批量删除用户失败", e);
            throw new BusinessException("批量删除用户失败");
        }
    }
}

六、分页查询实战

6.1 基础分页查询

@RestController
@RequestMapping("/user")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/page")
    public Result<Page<User>> getUserPage(
        @RequestParam(defaultValue = "1") Integer current,
        @RequestParam(defaultValue = "10") Integer size,
        @RequestParam(required = false) String userName,
        @RequestParam(required = false) String email) {
        
        Page<User> page = new Page<>(current, size);
        
        // 构建查询条件
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (StringUtils.hasText(userName)) {
            queryWrapper.like("user_name", userName);
        }
        if (StringUtils.hasText(email)) {
            queryWrapper.eq("email", email);
        }
        
        Page<User> userPage = userService.page(page, queryWrapper);
        
        return Result.success(userPage);
    }
}

6.2 复杂分页查询

@Service
public class UserQueryService {
    
    @Autowired
    private UserMapper userMapper;
    
    public Page<User> getUserPageWithCondition(
        Integer current,
        Integer size,
        String userName,
        String email,
        Integer age,
        LocalDateTime startTime,
        LocalDateTime endTime) {
        
        Page<User> page = new Page<>(current, size);
        
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        
        // 复杂查询条件
        if (StringUtils.hasText(userName)) {
            queryWrapper.like("user_name", userName);
        }
        if (StringUtils.hasText(email)) {
            queryWrapper.eq("email", email);
        }
        if (age != null) {
            queryWrapper.eq("age", age);
        }
        if (startTime != null && endTime != null) {
            queryWrapper.between("create_time", startTime, endTime);
        }
        
        // 排序
        queryWrapper.orderByDesc("create_time");
        
        return userMapper.selectPage(page, queryWrapper);
    }
    
    public Page<User> getUserWithDeptPage(Integer current, Integer size) {
        Page<User> page = new Page<>(current, size);
        
        // 使用自定义SQL进行关联查询
        String sql = "SELECT u.*, d.dept_name FROM user u LEFT JOIN department d ON u.dept_id = d.id";
        return userMapper.selectPage(page, sql);
    }
}

6.3 分页工具类封装

@Component
public class PageUtils {
    
    /**
     * 创建分页对象
     */
    public static <T> Page<T> createPage(Integer current, Integer size) {
        return new Page<>(current != null ? current : 1, 
                         size != null ? size : 10);
    }
    
    /**
     * 根据请求参数创建查询条件
     */
    public static QueryWrapper buildQueryWrapper(Map<String, Object> params) {
        QueryWrapper wrapper = new QueryWrapper();
        
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                
                if (value != null && !"".equals(value)) {
                    if (value instanceof String) {
                        wrapper.like(key, value);
                    } else {
                        wrapper.eq(key, value);
                    }
                }
            }
        }
        
        return wrapper;
    }
    
    /**
     * 分页结果包装
     */
    public static <T> Result<Page<T>> wrapPageResult(Page<T> page) {
        return Result.success(page);
    }
}

七、性能优化与监控

7.1 SQL执行监控

@Configuration
public class MyBatisConfig {
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        
        // 添加SQL拦截器用于监控
        interceptor.addInnerInterceptor(new SqlExplainInterceptor());
        
        return interceptor;
    }
    
    @Bean
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        // SQL执行时间超过1秒记录日志
        performanceInterceptor.setMaxTime(1000);
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
    }
}

7.2 缓存策略

@Service
public class CachedUserService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Cacheable(value = "users", key = "#userId")
    public User getUserById(Long userId) {
        return userMapper.selectById(userId);
    }
    
    @CacheEvict(value = "users", key = "#user.id")
    public boolean updateUser(User user) {
        return userMapper.updateById(user) > 0;
    }
    
    @CacheEvict(value = "users", allEntries = true)
    public void clearUserCache() {
        // 清空所有用户缓存
    }
}

7.3 批量操作优化

@Service
public class BatchOperationService {
    
    @Autowired
    private UserMapper userMapper;
    
    /**
     * 批量插入优化
     */
    public boolean batchInsertUsers(List<User> users) {
        return userMapper.insertBatchSomeColumn(users) > 0;
    }
    
    /**
     * 批量更新优化
     */
    public boolean batchUpdateUsers(List<User> users) {
        return userMapper.updateBatchById(users) > 0;
    }
    
    /**
     * 分批处理大量数据
     */
    public void processLargeData(List<Long> ids, int batchSize) {
        for (int i = 0; i < ids.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, ids.size());
            List<Long> batchIds = ids.subList(i, endIndex);
            
            // 批量处理逻辑
            processBatch(batchIds);
            
            // 添加延时避免数据库压力过大
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
    
    private void processBatch(List<Long> batchIds) {
        // 批量处理逻辑
        log.info("Processing batch: {}", batchIds.size());
    }
}

八、异常处理与日志记录

8.1 统一异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
    @ExceptionHandler(BusinessException.class)
    public Result<String> handleBusinessException(BusinessException e) {
        log.error("业务异常: {}", e.getMessage(), e);
        return Result.error(e.getMessage());
    }
    
    @ExceptionHandler(Exception.class)
    public Result<String> handleException(Exception e) {
        log.error("系统异常: ", e);
        return Result.error("系统异常,请稍后重试");
    }
    
    @ExceptionHandler(ValidationException.class)
    public Result<String> handleValidationException(ValidationException e) {
        log.warn("参数验证失败: {}", e.getMessage());
        return Result.error(e.getMessage());
    }
}

8.2 操作日志记录

@Aspect
@Component
public class LogAspect {
    
    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
    
    @Around("@annotation(com.example.enterprise.annotation.Log)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        
        try {
            Object result = joinPoint.proceed();
            
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            
            log.info("方法调用完成: {}.{},耗时: {}ms", className, methodName, duration);
            
            return result;
        } catch (Exception e) {
            log.error("方法调用异常: {}.{},异常信息: {}", className, methodName, e.getMessage(), e);
            throw e;
        }
    }
}

九、测试与部署

9.1 单元测试

@SpringBootTest
public class UserServiceTest {
    
    @Autowired
    private UserService userService;
    
    @Test
    public void testSaveUser() {
        User user = new User();
        user.setUserName("testUser");
        user.setEmail("test@example.com");
        user.setAge(25);
        
        boolean result = userService.saveUser(user);
        assertTrue(result);
        
        assertNotNull(user.getId());
    }
    
    @Test
    public void testGetUserByUsername() {
        User user = userService.getUserByUsername("testUser");
        assertNotNull(user);
        assertEquals("testUser", user.getUserName());
    }
}

9.2 集成测试

@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestPropertySource(locations = "classpath:application-test.yml")
public class IntegrationTest {
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    public void testUserApi() {
        ResponseEntity<User> response = restTemplate.getForEntity("/user/1", User.class);
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertNotNull(response.getBody());
    }
}

十、总结与最佳实践

通过本文的详细介绍,我们已经全面了解了Spring Boot与MyBatis Plus在企业级应用开发中的最佳实践。从基础配置到高级功能,从性能优化到异常处理,每一个环节都体现了技术选型的合理性和实用性。

核心要点总结:

  1. 配置规范化:合理的项目结构和配置文件管理是成功的基础
  2. 代码生成器:有效提升开发效率,减少重复劳动
  3. 分页查询:处理大数据量的关键技术
  4. 事务管理:保证数据一致性的核心机制
  5. 性能优化:从SQL监控到缓存策略的全方位优化
  6. 异常处理:完善的错误处理机制提升系统稳定性

在实际项目中,建议根据具体业务需求灵活运用这些最佳实践,同时保持对新技术的关注和学习,持续优化系统架构和开发流程。Spring Boot + MyBatis Plus的组合不仅能够满足当前的开发需求,也为未来的扩展和维护提供了良好的基础。

通过合理的设计和规范化的开发流程,我们可以构建出既高效又稳定的Java企业级应用系统,为业务发展提供强有力的技术支撑。

相关推荐
广告位招租

相似文章

    评论 (0)

    0/2000