引言
在现代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 <= #{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在企业级应用开发中的最佳实践。从基础配置到高级功能,从性能优化到异常处理,每一个环节都体现了技术选型的合理性和实用性。
核心要点总结:
- 配置规范化:合理的项目结构和配置文件管理是成功的基础
- 代码生成器:有效提升开发效率,减少重复劳动
- 分页查询:处理大数据量的关键技术
- 事务管理:保证数据一致性的核心机制
- 性能优化:从SQL监控到缓存策略的全方位优化
- 异常处理:完善的错误处理机制提升系统稳定性
在实际项目中,建议根据具体业务需求灵活运用这些最佳实践,同时保持对新技术的关注和学习,持续优化系统架构和开发流程。Spring Boot + MyBatis Plus的组合不仅能够满足当前的开发需求,也为未来的扩展和维护提供了良好的基础。
通过合理的设计和规范化的开发流程,我们可以构建出既高效又稳定的Java企业级应用系统,为业务发展提供强有力的技术支撑。

评论 (0)