SpringBoot分布式项目中MyBatis实战技巧:从配置到性能优化

引言

在分布式系统架构中,SpringBoot与MyBatis的组合已成为企业级开发的黄金搭档。但在实际项目中,开发者常面临多数据源管理、SQL性能优化、分布式事务等挑战。本文将从实战角度出发,分享7个关键技巧和避坑指南。


一、多数据源动态切换实战

1.1 多数据源配置

java 复制代码
@Configuration
public class DataSourceConfig {
    
    @Bean(name = "masterDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

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

1.2 动态数据源路由

java 复制代码
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceType();
    }
}

// 使用AOP实现自动切换
@Around("execution(* com.example.service..*.*(..))")
public Object around(ProceedingJoinPoint point) {
    MethodSignature signature = (MethodSignature) point.getSignature();
    DataSourceSwitch dataSource = signature.getMethod().getAnnotation(DataSourceSwitch.class);
    
    if(dataSource != null){
        DataSourceContextHolder.setDataSourceType(dataSource.value());
    }
    // 执行方法...
}

注意点

  • 事务管理需使用@Transactional(transactionManager = "txManager")
  • 连接池推荐使用HikariCP
  • 读写分离场景建议结合AbstractRoutingDataSource+注解方式

二、MyBatis进阶使用技巧

2.1 动态SQL最佳实践

xml 复制代码
<select id="searchUsers" resultType="User">
  SELECT * FROM users
  <where>
    <if test="name != null">
      AND name LIKE CONCAT('%',#{name},'%')
    </if>
    <if test="status != null">
      AND status = #{status}
    </if>
    <choose>
      <when test="orderBy == 'name'">
        ORDER BY name
      </when>
      <otherwise>
        ORDER BY create_time DESC
      </otherwise>
    </choose>
  </where>
</select>

2.2 自定义TypeHandler

处理枚举类型和加密字段:

java 复制代码
public class EncryptTypeHandler extends BaseTypeHandler<String> {
    private final Encryptor encryptor = new AESEncryptor();

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, 
                                    String parameter, JdbcType jdbcType) {
        ps.setString(i, encryptor.encrypt(parameter));
    }
    
    // 其他方法实现解密...
}

// 实体类使用
public class User {
    @TableField(typeHandler = EncryptTypeHandler.class)
    private String mobile;
}

三、性能优化三板斧

3.1 批量插入优化

java 复制代码
public void batchInsert(List<User> users) {
    SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory()
            .openSession(ExecutorType.BATCH);
    try {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        for (User user : users) {
            mapper.insert(user);
        }
        sqlSession.commit();
    } finally {
        sqlSession.close();
    }
}

3.2 二级缓存配置

xml 复制代码
<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>

<!-- Mapper级别开启 -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

缓存策略建议

  • 读多写少的数据适合开启缓存
  • 分布式环境建议集成Redis
  • 及时清理关联表的缓存数据

四、分布式项目中的特殊处理

4.1 分页查询优化

java 复制代码
// 使用PageHelper实现物理分页
PageHelper.startPage(1, 10, "id DESC");
List<User> users = userMapper.selectByCondition(condition);
PageInfo<User> pageInfo = new PageInfo<>(users);

// 深度分页优化(基于游标)
@Select("SELECT * FROM users WHERE id > #{lastId} ORDER BY id LIMIT #{size}")
List<User> selectByScroll(@Param("lastId") Long lastId, @Param("size") int size);

4.2 SQL拦截器开发

公共字段自动填充插件示例:

java 复制代码
@Intercepts({
    @Signature(type = Executor.class, method = "update", 
              args = {MappedStatement.class, Object.class})
})
public class AutoFillInterceptor implements Interceptor {
    
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object parameter = invocation.getArgs()[1];
        if(parameter instanceof BaseEntity){
            BaseEntity entity = (BaseEntity) parameter;
            entity.setUpdateTime(new Date());
            entity.setUpdater(getCurrentUser());
        }
        return invocation.proceed();
    }
}

五、避坑指南

5.1 警惕N+1查询问题

xml 复制代码
<!-- 错误示范 -->
<resultMap id="userMap" type="User">
    <collection property="orders" 
                select="selectOrdersByUserId" column="id"/>
</resultMap>

<!-- 正确方案:使用JOIN查询 -->
<select id="selectUserWithOrders" resultMap="userOrderMap">
    SELECT u.*, o.* 
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
</select>

5.2 事务使用原则

  • 方法间调用避免this调用导致AOP失效
  • 只读事务添加@Transactional(readOnly = true)
  • 分布式事务建议使用Seata方案

结语

在SpringBoot分布式架构中,合理运用MyBatis的特性可以显著提升开发效率和系统性能。但切记:

  1. 多数据源配置要处理好事务边界
  2. 动态SQL保持简洁可维护
  3. 缓存策略需结合业务特点
  4. 监控慢SQL(推荐使用p6spy)

下一期预告:《SpringBoot+MyBatis整合Redis二级缓存实战》------我们将深入探讨如何构建高性能分布式缓存方案。

相关推荐
Database_Cool_10 小时前
单机 MySQL 迁移到分布式数据库方便吗?阿里云 PolarDB-X 100% MySQL 协议兼容零改造平滑迁移
数据库·分布式·mysql
Java内核笔记15 小时前
告别十亿美元的错误 : Spring Boot 4 空安全 (JSpecify) 实战
java·spring boot·后端
海棠Flower未眠17 小时前
SpringBoot 消息死信队列(荣耀典藏版)
java·数据库·spring boot
腾渊信息科技公司17 小时前
Spring Boot + TDengine:工业视觉检测数据实时同步方案实战
spring boot·后端·tdengine
weixin_BYSJ198719 小时前
「课设设计」springboot校园超市助购系统26449 (附源码)
java·javascript·spring boot·python·django·flask·php
肥胖小羊20 小时前
解决企业微信 AccessToken 刷新并发冲突的分布式锁机制实践
分布式·企业微信
奈何不吃鱼1 天前
【SpringBoot】业务多线程四大实战场景
java·spring boot·多线程
奶糖 肥晨1 天前
一次Spring Boot编译报错排查:三元运算符与包装类型的“隐形陷阱”
java·spring boot·后端
一只小小Java1 天前
Naocs本地部署&安装3.2.3+Spring boot 3.2.0
java·spring boot·后端·nacos
JL151 天前
Spring Boot vs Gin:Java 人搭第一个 Go REST API
java·spring boot·gin