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 集成