1. 为什么选择MyBatis-Flex与SpringBoot整合
MyBatis-Flex作为MyBatis的增强框架,在传统ORM基础上提供了更灵活的动态SQL支持。与SpringBoot这个"约定优于配置"的微服务框架结合,能显著提升开发效率。我在实际项目中发现,这种组合特别适合需要快速迭代的中小型项目。
传统MyBatis需要手动编写大量XML映射文件,而MyBatis-Flex通过注解和链式API,让代码量减少40%以上。比如多表联查场景,原先需要写复杂的resultMap,现在通过@Table注解和Relations注解就能轻松实现。
2. 环境准备与项目初始化
2.1 必备工具清单
- JDK 1.8+(推荐Amazon Corretto 17)
- IntelliJ IDEA 2023.2+(社区版足够)
- Maven 3.6.3+
- MySQL 8.0+(或H2内存数据库用于测试)
2.2 创建SpringBoot项目
通过start.spring.io生成项目时,除了选择Web和MySQL驱动外,特别注意:
- 使用SpringBoot 2.7.x版本(目前最稳定)
- 打包方式选jar
- Java版本选17
<!-- pom.xml关键依赖 --> <dependency> <groupId>com.mybatis-flex</groupId> <artifactId>mybatis-flex-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency>3. 核心配置详解
3.1 数据源配置
application.yml中需要特别注意连接池配置:
spring: datasource: url: jdbc:mysql://localhost:3306/flex_demo?useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 hikari: maximum-pool-size: 20 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000 mybatis-flex: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启SQL日志3.2 实体类映射
User实体类的注解配置示例:
@Table("sys_user") public class User { @Id(keyType = KeyType.Auto) private Long id; @Column("username") private String name; @Column(onInsertValue = "now()") private LocalDateTime createTime; // 关联部门(1对1) @RelationOneToOne(selfField = "deptId", targetField = "id") private Department department; }4. 增删改查实战
4.1 基础CRUD操作
// 插入(自动填充创建时间) User user = new User(); user.setName("张三"); userMapper.insert(user); // 条件更新 User updateUser = new User(); updateUser.setId(1L); updateUser.setName("李四"); userMapper.update(updateUser); // 链式查询 List<User> users = userMapper.selectListByQuery( Query.create().where(User::getName).like("张") .and(User::getCreateTime).ge(LocalDate.now()) .orderBy(User::getId, false) );4.2 复杂查询示例
多表联查的三种实现方式:
- 注解关联(推荐):
@Table("sys_order") public class Order { @RelationManyToOne(selfField = "userId", targetField = "id") private User user; }- 手动Join:
QueryWrapper query = QueryWrapper.create() .select(ORDER.ALL_COLUMNS, USER.USER_NAME) .from(ORDER) .leftJoin(USER).on(ORDER.USER_ID.eq(USER.ID)) .where(ORDER.AMOUNT.gt(1000));- 子查询:
QueryWrapper query = QueryWrapper.create() .select() .from(USER) .where(USER.ID.in( select(ORDER.USER_ID).from(ORDER).where(ORDER.STATUS.eq(1)) ));5. 高级特性应用
5.1 动态表名
适合多租户场景:
public class TenantTable implements TableProcessor { @Override public String process(String tableName) { return TenantContext.getTenantId() + "_" + tableName; } } // 配置启用 mybatis-flex: table-processor: com.example.TenantTable5.2 逻辑删除
全局配置逻辑删除字段:
mybatis-flex: global-config: logic-delete: column: is_deleted logic-not-delete-value: 0 logic-delete-value: 15.3 数据脱敏
使用@ColumnMask注解:
@ColumnMask(Masks.CHINESE_NAME) private String realName; @ColumnMask(Masks.MOBILE) private String phone;6. 性能优化建议
- 批量操作使用executeBatch:
try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) { UserMapper mapper = session.getMapper(UserMapper.class); for (int i = 0; i < 1000; i++) { mapper.insert(new User("user"+i)); } session.commit(); }- 复杂查询开启二级缓存:
@Cache(flushInterval = 300000) // 5分钟刷新 public interface UserMapper extends BaseMapper<User> { @Cache List<User> selectSpecialUsers(); }- 避免N+1查询:
// 错误做法(会触发N+1) List<Order> orders = orderMapper.selectAll(); orders.forEach(o -> System.out.println(o.getUser().getName())); // 正确做法(一次加载) List<Order> orders = orderMapper.selectListWithRelations( Query.create().all().withRelations("user") );7. 常见问题排查
7.1 字段映射失败
症状:查询结果字段为null 排查步骤:
- 检查@Column注解的value是否与数据库列名一致
- 确认数据库字段是否为下划线命名(默认开启下划线转驼峰)
- 在application.yml添加配置:
mybatis-flex: configuration: map-underscore-to-camel-case: true7.2 事务不生效
确保:
- 主类有@EnableTransactionManagement
- 方法上有@Transactional
- 不要try-catch吞掉异常
- 同类方法调用走代理(通过@Autowired注入自己)
7.3 分页查询异常
正确使用姿势:
Page<User> page = Page.of(1, 10); // 第1页,每页10条 QueryWrapper query = QueryWrapper.create() .where(User::getStatus).eq(1) .orderBy(User::getId.desc()); Page<User> result = userMapper.paginate(page, query);8. 生产环境建议
- 监控SQL性能:
mybatis-flex: metrics: enabled: true logger: enabled: true level: warn warn-time: 1000 # 超过1秒的SQL告警- 多数据源配置:
@Configuration @MapperScan(basePackages = "com.dao.db1", sqlSessionFactoryRef = "db1SqlSessionFactory") public class Db1Config { @Bean @ConfigurationProperties("spring.datasource.db1") public DataSource db1DataSource() { return DataSourceBuilder.create().build(); } @Bean public SqlSessionFactory db1SqlSessionFactory() throws Exception { MybatisFlexSqlSessionFactoryBean factory = new MybatisFlexSqlSessionFactoryBean(); factory.setDataSource(db1DataSource()); return factory.getObject(); } }- 线上问题排查工具:
- 开启SQL日志时添加MDC标记:
logging: pattern: console: "%d{yyyy-MM-dd HH:mm:ss} [%X{traceId}] %-5level %logger{36} - %msg%n"我在实际项目中发现,MyBatis-Flex的@Relation注解虽然方便,但在处理超大规模数据关联时(10万+记录)会有性能问题。这时建议改用手动Join配合分页查询。另外,字段加密功能对模糊查询支持有限,如果业务需要模糊搜索加密字段,可以考虑在数据库层使用加密函数索引。