引言
在现代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)