跳到主要内容
版本:v2

framework-starter-mybatis - MyBatis 自动配置模块

1. 模块概述

framework-starter-mybatis 是 epoch-framework 中的 MyBatis 自动配置模块,基于 MyBatis 和 MyBatis Plus 实现,提供了数据库访问的自动配置和集成支持。该模块通过约定大于配置的方式,简化了 MyBatis 在 Spring Boot 应用中的使用,支持 CRUD 操作、分页、性能分析等功能。

2. 模块结构

framework-starter-mybatis/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/epoch/framework/starter/mybatis/
│ │ │ ├── config/ # 自动配置类
│ │ │ ├── handler/ # 类型处理器
│ │ │ ├── plugin/ # MyBatis 插件
│ │ │ ├── interceptor/ # MyBatis 拦截器
│ │ │ └── support/ # 支持工具类
│ │ └── resources/
│ │ └── META-INF/
│ │ └── spring.factories # Spring Boot 自动配置入口
│ └── test/ # 测试代码
└── pom.xml # Maven 依赖配置

3. 核心功能

3.1 SqlSessionFactory 自动配置

  • 自动创建和配置 SqlSessionFactory 实例
  • 集成 MyBatis Plus 增强功能
  • 支持多数据源配置
  • 提供默认的 MyBatis 配置策略

3.2 事务管理器自动配置

  • 集成 Spring 声明式事务
  • 自动配置事务管理器
  • 支持事务传播行为和隔离级别配置
  • 提供事务日志和监控支持

3.3 MyBatis Plus 增强

  • 自动配置 MyBatis Plus 核心功能
  • 支持代码生成器集成
  • 提供条件构造器、分页插件等增强功能
  • 支持逻辑删除、乐观锁等高级特性

3.4 分页插件自动配置

  • 集成 MyBatis Plus 分页插件
  • 支持自定义分页参数和结果
  • 提供分页信息的统一封装
  • 支持多数据源分页

3.5 性能分析插件

  • 提供 SQL 执行性能分析
  • 支持慢 SQL 监控和报警
  • 提供 SQL 执行时间统计
  • 支持开发环境和生产环境切换

3.6 类型处理器

  • 提供常用类型处理器的自动配置
  • 支持枚举、日期、JSON 等类型的处理
  • 支持自定义类型处理器的注册

4. 配置说明

4.1 基础数据源配置

spring:
datasource:
url: jdbc:mysql://localhost:3306/epoch?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 5
maximum-pool-size: 20
auto-commit: true
idle-timeout: 30000
pool-name: EpochHikariCP
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1

4.2 MyBatis Plus 配置

mybatis-plus:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.epoch.model
global-config:
db-config:
id-type: AUTO
table-prefix: t_
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
lazy-loading-enabled: false
multiple-result-sets-enabled: true
use-generated-keys: true
default-executor-type: REUSE
default-statement-timeout: 60

4.3 性能分析配置

epoch:
framework:
mybatis:
performance:
enabled: true
max-execution-time: 5000
format: true
write-in-log: true

4.4 分页配置

epoch:
framework:
mybatis:
page:
auto-optimize-count: true
reasonable: true
support-methods-arguments: true
params: page=currentPage;limit=pageSize
count-sql-parser: com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize

5. 使用指南

5.1 引入依赖

<dependency>
<groupId>com.epoch</groupId>
<artifactId>framework-starter-mybatis</artifactId>
<version>${epoch.version}</version>
</dependency>

5.2 实体类定义

@Data
@TableName("t_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String password;
private String email;
private Integer status;
private LocalDateTime createTime;
private LocalDateTime updateTime;
@TableLogic
private Integer deleted;
}

5.3 Mapper 接口定义

@Mapper
public interface UserMapper extends BaseMapper<User> {
// 继承 BaseMapper 后即可使用常用的 CRUD 方法

// 自定义查询方法
List<User> selectByStatus(@Param("status") Integer status);

// 分页查询方法
IPage<User> selectPageByStatus(IPage<User> page, @Param("status") Integer status);
}

5.4 Service 层实现

@Service
public class UserService extends ServiceImpl<UserMapper, User> {
// 继承 ServiceImpl 后即可使用常用的 Service 方法

public User getUserById(Long id) {
return baseMapper.selectById(id);
}

public List<User> getUserListByStatus(Integer status) {
return baseMapper.selectByStatus(status);
}

public Page<User> getUserPage(Page<User> page, Integer status) {
return baseMapper.selectPageByStatus(page, status);
}

public boolean saveUser(User user) {
return save(user);
}

public boolean updateUser(User user) {
return updateById(user);
}

public boolean deleteUser(Long id) {
return removeById(id);
}
}

5.5 Controller 层使用

@RestController
@RequestMapping("/user")
public class UserController {

@Autowired
private UserService userService;

@GetMapping("/{id}")
public ResponseResult getUserById(@PathVariable Long id) {
User user = userService.getUserById(id);
return ResponseResult.success(user);
}

@GetMapping("/list")
public ResponseResult getUserList(@RequestParam(required = false) Integer status) {
List<User> userList = userService.getUserListByStatus(status);
return ResponseResult.success(userList);
}

@GetMapping("/page")
public ResponseResult getUserPage(@RequestParam(defaultValue = "1") Integer current,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(required = false) Integer status) {
Page<User> page = new Page<>(current, size);
Page<User> userPage = userService.getUserPage(page, status);
return ResponseResult.success(userPage);
}

@PostMapping
public ResponseResult saveUser(@RequestBody User user) {
boolean result = userService.saveUser(user);
return ResponseResult.success(result);
}

@PutMapping
public ResponseResult updateUser(@RequestBody User user) {
boolean result = userService.updateUser(user);
return ResponseResult.success(result);
}

@DeleteMapping("/{id}")
public ResponseResult deleteUser(@PathVariable Long id) {
boolean result = userService.deleteUser(id);
return ResponseResult.success(result);
}
}

5.6 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.epoch.mapper.UserMapper">

<select id="selectByStatus" resultType="com.epoch.model.User">
SELECT * FROM t_user WHERE status = #{status} AND deleted = 0
</select>

<select id="selectPageByStatus" resultType="com.epoch.model.User">
SELECT * FROM t_user WHERE status = #{status} AND deleted = 0
</select>
</mapper>

5.7 条件构造器使用

public List<User> getUserListByCondition(String username, Integer status) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(username)) {
wrapper.like("username", username);
}
if (status != null) {
wrapper.eq("status", status);
}
wrapper.eq("deleted", 0)
.orderByDesc("create_time");
return list(wrapper);
}

6. 自定义配置

6.1 自定义 MyBatis 配置

@Configuration
public class MyBatisConfig {

@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> {
// 开启驼峰命名转换
configuration.setMapUnderscoreToCamelCase(true);
// 开启缓存
configuration.setCacheEnabled(false);
// 设置默认执行器类型
configuration.setDefaultExecutorType(ExecutorType.REUSE);
// 设置默认超时时间
configuration.setDefaultStatementTimeout(60);
};
}
}

6.2 自定义插件

@Configuration
public class MyBatisPluginConfig {

@Bean
public MyInterceptor myInterceptor() {
return new MyInterceptor();
}

@Bean
public InterceptorRegistration myInterceptorRegistration(MyInterceptor myInterceptor) {
InterceptorRegistration registration = new InterceptorRegistration();
registration.setInterceptor(myInterceptor);
// 设置拦截器属性
registration.addProperty("property1", "value1");
registration.addProperty("property2", "value2");
return registration;
}
}

6.3 多数据源配置

@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = "com.epoch.mapper.master", sqlSessionTemplateRef = "masterSqlSessionTemplate")
public class MasterDataSourceConfig {

@Bean("masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}

@Bean("masterSqlSessionFactory")
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/master/*.xml"));
return bean.getObject();
}

@Bean("masterTransactionManager")
public DataSourceTransactionManager masterTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}

@Bean("masterSqlSessionTemplate")
public SqlSessionTemplate masterSqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

7. 最佳实践

7.1 实体类设计

  • 使用 @TableName 指定数据库表名
  • 使用 @TableId 指定主键生成策略
  • 使用 @TableField 指定字段映射关系
  • 合理使用 @TableLogic 实现逻辑删除

7.2 Mapper 接口设计

  • 继承 BaseMapper 获取常用 CRUD 方法
  • 自定义方法使用 @Param 指定参数名称
  • 复杂查询使用 XML 映射文件
  • 分页查询返回 IPage 接口

7.3 Service 层设计

  • 继承 ServiceImpl 获取常用 Service 方法
  • 使用 baseMapper 直接调用 Mapper 方法
  • 业务逻辑封装在 Service 层
  • 合理使用事务注解 @Transactional

7.4 性能优化

  • 使用分页查询减少数据传输
  • 合理使用索引优化 SQL
  • 避免 SELECT * 查询,只查询需要的字段
  • 批量操作使用 MyBatis Plus 的批量方法
  • 开启性能分析插件监控 SQL 执行效率

7.5 事务管理

  • 在 Service 层使用 @Transactional 注解
  • 合理设置事务传播行为和隔离级别
  • 避免在循环中使用事务
  • 事务范围尽量小,只包含必要的操作

8. 常见问题

8.1 实体类与数据库表映射失败

原因:实体类与数据库表名、字段名不匹配。

解决方案

  • 使用 @TableName 指定表名
  • 使用 @TableField 指定字段映射
  • 开启驼峰命名转换配置

8.2 分页查询无效

原因:分页插件配置不正确或使用方式错误。

解决方案

  • 检查分页插件是否正确配置
  • 使用 Page 对象作为方法参数
  • 确保方法返回值为 IPage 类型

8.3 事务不生效

原因:事务注解配置不正确或方法调用方式错误。

解决方案

  • 检查 @Transactional 注解是否正确
  • 确保方法是 public 修饰的
  • 避免内部方法调用导致事务失效
  • 检查事务管理器是否正确配置

8.4 SQL 执行性能差

原因:SQL 语句优化不足或索引使用不当。

解决方案

  • 开启性能分析插件
  • 优化 SQL 语句,避免全表扫描
  • 合理创建索引
  • 使用分页查询减少数据量

9. 版本变更

9.1 主要变更

  • 3.4.0

    • 完善 MyBatis 自动配置,增加性能分析插件支持
    • 优化分页插件配置,支持更灵活的分页参数
    • 更新 MyBatis Plus 版本至 3.5.17
    • 增加多数据源支持
  • 3.3.0

    • 优化 MyBatis 配置,提高可扩展性
    • 增加类型处理器支持
    • 完善事务管理配置
  • 3.2.0

    • 初始版本,提供 MyBatis 自动配置和 MyBatis Plus 集成