Spring Boot + MyBatis Plus 最佳实践:从代码生成到性能调优的完整指南

LowQuinn
LowQuinn 2026-02-04T00:01:09+08:00
0 0 0

引言

在现代Java后端开发中,Spring Boot与MyBatis Plus的组合已成为构建高效、稳定应用系统的首选方案。Spring Boot以其"约定优于配置"的理念简化了Spring应用的初始搭建和开发过程,而MyBatis Plus作为MyBatis的增强工具,提供了丰富的CRUD操作和强大的代码生成能力。

本文将深入探讨Spring Boot与MyBatis Plus的完整技术栈实践,从基础的代码生成开始,逐步深入到分页查询优化、SQL性能调优以及缓存策略等高级话题。通过实际项目案例,我们将展示如何构建既高效又稳定的后端服务,全面提升开发效率和系统性能。

一、Spring Boot + MyBatis Plus 环境搭建

1.1 项目依赖配置

首先,我们需要在pom.xml中添加必要的依赖:

<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- MyBatis Plus -->
    <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>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
    </dependency>
    
    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </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/test_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
  global-config:
    db-config:
      id-type: auto

二、代码自动生成实践

2.1 MyBatis Plus Generator 配置

MyBatis Plus提供了强大的代码生成器,可以一键生成实体类、Mapper接口、Service层和Controller层代码:

@Configuration
public class MyBatisPlusGenerator {
    
    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("author");
        gc.setOpen(false);
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);
        
        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/test_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("password");
        mpg.setDataSource(ddsc);
        
        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("user");
        pc.setParent("com.example.demo");
        mpg.setPackageInfo(pc);
        
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setInclude("user", "role"); // 指定生成的表
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        
        mpg.execute();
    }
}

2.2 自动生成的代码结构

通过代码生成器,我们可以得到以下结构:

// 实体类 User.java
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("user")
public class User implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    
    private String name;
    
    private Integer age;
    
    private String email;
}

// Mapper 接口 UserMapper.java
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

// Service 接口 UserService.java
public interface UserService extends IService<User> {
}

// Service 实现类 UserServiceImpl.java
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

三、分页查询优化策略

3.1 基础分页查询

MyBatis Plus内置了强大的分页插件,使用非常简单:

@RestController
@RequestMapping("/user")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/page")
    public IPage<User> getUserPage(int current, int size) {
        Page<User> page = new Page<>(current, size);
        return userService.page(page);
    }
}

3.2 自定义分页查询

对于复杂的业务场景,我们可能需要自定义分页查询:

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    public IPage<UserVO> getUserPageWithCondition(int current, int size, String name) {
        Page<User> page = new Page<>(current, size);
        
        // 构建查询条件
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(name)) {
            wrapper.like("name", name);
        }
        
        // 执行分页查询
        IPage<User> userPage = this.page(page, wrapper);
        
        // 转换为VO对象
        List<UserVO> userVOList = userPage.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
                
        IPage<UserVO> result = new Page<>();
        result.setRecords(userVOList);
        result.setTotal(userPage.getTotal());
        result.setSize(userPage.getSize());
        result.setCurrent(userPage.getCurrent());
        
        return result;
    }
    
    private UserVO convertToVO(User user) {
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(user, vo);
        // 进行其他转换逻辑
        return vo;
    }
}

3.3 分页性能优化

针对大数据量的分页查询,我们需要考虑以下优化策略:

// 使用游标分页避免OFFSET过大
public IPage<User> getCursorPage(int size, Long lastId) {
    Page<User> page = new Page<>(1, size);
    
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    if (lastId != null) {
        wrapper.gt("id", lastId);
    }
    wrapper.orderByAsc("id");
    
    return this.page(page, wrapper);
}

// 分页查询优化配置
@Configuration
public class MyBatisPlusConfig {
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        
        // 分页插件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        paginationInnerInterceptor.setOverflow(true);
        paginationInnerInterceptor.setMaxLimit(1000L);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        
        return interceptor;
    }
}

四、SQL性能调优实践

4.1 SQL执行分析工具

MyBatis Plus提供了详细的SQL执行日志,帮助我们分析性能问题:

# 开启SQL日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

4.2 常见SQL优化技巧

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    // 1. 避免SELECT *,明确指定字段
    public List<User> getUsersByIds(List<Long> ids) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.select("id", "name", "email"); // 明确指定字段
        wrapper.in("id", ids);
        return this.list(wrapper);
    }
    
    // 2. 合理使用索引
    public List<User> getUsersByAgeRange(int minAge, int maxAge) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        // 假设age字段上有索引
        wrapper.between("age", minAge, maxAge);
        return this.list(wrapper);
    }
    
    // 3. 批量操作优化
    public void batchInsertUsers(List<User> users) {
        // 使用批量插入
        this.saveBatch(users, 1000); // 每批1000条记录
    }
    
    // 4. 使用原生SQL优化复杂查询
    @Select("SELECT u.id, u.name, u.email, 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.status = #{status} AND u.create_time >= #{startTime}")
    List<UserRoleVO> getUsersWithRoles(@Param("status") Integer status, 
                                     @Param("startTime") Date startTime);
}

4.3 复杂查询优化

对于复杂的业务查询,我们可以使用自定义SQL:

@Mapper
public interface UserMapper extends BaseMapper<User> {
    
    // 使用XML配置复杂查询
    List<UserVO> selectUserWithDetail(@Param("userId") Long userId);
}

// XML文件 user-mapper.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.demo.mapper.UserMapper">
    
    <select id="selectUserWithDetail" resultType="com.example.demo.vo.UserVO">
        SELECT 
            u.id,
            u.name,
            u.email,
            u.age,
            GROUP_CONCAT(r.role_name) as roles
        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}
        GROUP BY u.id, u.name, u.email, u.age
    </select>
    
</mapper>

五、缓存策略与实现

5.1 Spring Cache 集成

@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .maximumSize(1000)
                .expireAfterWrite(30, TimeUnit.MINUTES)
                .recordStats());
        return cacheManager;
    }
}

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    @Cacheable(value = "users", key = "#id")
    public User getUserById(Long id) {
        return this.getById(id);
    }
    
    @CacheEvict(value = "users", key = "#user.id")
    public void updateUser(User user) {
        this.updateById(user);
    }
    
    @Cacheable(value = "userPage", key = "#current + '_' + #size + '_' + #name")
    public IPage<User> getUserPage(int current, int size, String name) {
        Page<User> page = new Page<>(current, size);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(name)) {
            wrapper.like("name", name);
        }
        return this.page(page, wrapper);
    }
}

5.2 多级缓存实现

@Component
public class MultiLevelCacheService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private UserService userService;
    
    public User getUserWithMultiCache(Long userId) {
        // 1. 先从本地缓存获取
        String cacheKey = "user:" + userId;
        User user = (User) localCache.get(cacheKey);
        
        if (user != null) {
            return user;
        }
        
        // 2. 从Redis获取
        user = (User) redisTemplate.opsForValue().get(cacheKey);
        if (user != null) {
            // 3. 同步到本地缓存
            localCache.put(cacheKey, user);
            return user;
        }
        
        // 4. 从数据库获取并写入缓存
        user = userService.getUserById(userId);
        if (user != null) {
            redisTemplate.opsForValue().set(cacheKey, user, 30, TimeUnit.MINUTES);
            localCache.put(cacheKey, user);
        }
        
        return user;
    }
    
    // 缓存清理策略
    public void clearUserCache(Long userId) {
        String cacheKey = "user:" + userId;
        redisTemplate.delete(cacheKey);
        localCache.invalidate(cacheKey);
    }
}

六、事务管理与异常处理

6.1 事务配置

@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    @Autowired
    private RoleService roleService;
    
    public void createUserWithRole(User user, Long roleId) {
        // 保存用户
        this.save(user);
        
        // 关联角色
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(roleId);
        roleService.saveUserRole(userRole);
    }
}

6.2 全局异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException e) {
        ErrorResponse error = new ErrorResponse(e.getCode(), e.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
    }
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception e) {
        log.error("系统异常", e);
        ErrorResponse error = new ErrorResponse(500, "系统内部错误");
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
    }
}

// 自定义业务异常
public class BusinessException extends RuntimeException {
    private int code;
    
    public BusinessException(int code, String message) {
        super(message);
        this.code = code;
    }
    
    // getter and setter
}

七、监控与日志实践

7.1 SQL监控配置

# 开启SQL监控
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    # 开启SQL性能监控
    auto-mapping-behavior: partial

7.2 自定义日志记录

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    
    @Transactional
    public User createUser(User user) {
        long startTime = System.currentTimeMillis();
        
        try {
            // 业务逻辑
            this.save(user);
            
            long endTime = System.currentTimeMillis();
            logger.info("创建用户成功,耗时:{}ms, 用户ID:{}", 
                       (endTime - startTime), user.getId());
            
            return user;
        } catch (Exception e) {
            logger.error("创建用户失败,用户信息:{}", user, e);
            throw new BusinessException(500, "创建用户失败");
        }
    }
}

八、性能测试与调优

8.1 基准测试

@SpringBootTest
public class PerformanceTest {
    
    @Autowired
    private UserService userService;
    
    @Test
    public void testUserQueryPerformance() {
        // 测试分页查询性能
        long startTime = System.currentTimeMillis();
        
        for (int i = 0; i < 100; i++) {
            Page<User> page = new Page<>(1, 10);
            userService.page(page);
        }
        
        long endTime = System.currentTimeMillis();
        System.out.println("100次分页查询耗时:" + (endTime - startTime) + "ms");
    }
}

8.2 数据库连接池优化

@Configuration
public class DataSourceConfig {
    
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public HikariDataSource dataSource() {
        return new HikariDataSource();
    }
}

结语

通过本文的详细介绍,我们全面展示了Spring Boot与MyBatis Plus在实际项目中的最佳实践。从基础的环境搭建到代码生成,从分页查询优化到SQL性能调优,再到缓存策略和事务管理,每一个环节都体现了现代Java后端开发的技术精髓。

掌握这些技术要点,不仅能够显著提升开发效率,还能确保系统具备良好的性能表现和稳定的运行能力。在实际项目中,我们需要根据具体的业务场景和性能要求,灵活运用这些技术手段,持续优化系统架构。

未来,随着微服务架构的普及和技术的不断发展,Spring Boot + MyBatis Plus的技术栈将继续演进。保持对新技术的学习和实践,将是每个开发者持续进步的关键。希望本文能够为您的技术成长提供有价值的参考和指导。

相关推荐
广告位招租

相似文章

    评论 (0)

    0/2000