在分布式系统架构中,SpringBoot与MyBatis的组合已成为企业级开发的黄金搭档。但在实际项目中,开发者常面临多数据源管理、SQL性能优化、分布式事务等挑战。
1.1 多数据源配置
@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 动态数据源路由
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());
}
// 执行方法...
}
注意点:
2.1 动态SQL最佳实践
<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
处理枚举类型和加密字段:
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 批量插入优化
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 二级缓存配置
<settings>
<setting name="cacheEnabled" value="true"/>
settings>
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
缓存策略建议:
4.1 分页查询优化
// 使用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拦截器开发
公共字段自动填充插件示例:
@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查询问题
<resultMap id="userMap" type="User">
<collection property="orders"
select="selectOrdersByUserId" column="id"/>
resultMap>
<select id="selectUserWithOrders" resultMap="userOrderMap">
SELECT u.*, o.*
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
select>
5.2 事务使用原则