引言
在分布式系統架構中,SpringBoot與MyBatis的組合已成為企業級開發的黃金搭檔。但在實際項目中,開發者常面臨多數據源管理、SQL性能優化、分布式事務等挑戰。本文將從實戰角度出發,分享7個關鍵技巧和避坑指南。
一、多數據源動態切換實戰
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 {@Overrideprotected 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最佳實踐
<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();@Overridepublic 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><!-- Mapper級別開啟 -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
緩存策略建議:
- 讀多寫少的數據適合開啟緩存
- 分布式環境建議集成Redis
- 及時清理關聯表的緩存數據
四、分布式項目中的特殊處理
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 {@Overridepublic 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><!-- 正確方案:使用JOIN查詢 -->
<select id="selectUserWithOrders" resultMap="userOrderMap">SELECT u.*, o.* FROM users uLEFT JOIN orders o ON u.id = o.user_id
</select>
5.2 事務使用原則
- 方法間調用避免this調用導致AOP失效
- 只讀事務添加@Transactional(readOnly = true)
- 分布式事務建議使用Seata方案
結語
在SpringBoot分布式架構中,合理運用MyBatis的特性可以顯著提升開發效率和系統性能。但切記:
- 多數據源配置要處理好事務邊界
- 動態SQL保持簡潔可維護
- 緩存策略需結合業務特點
- 監控慢SQL(推薦使用p6spy)
下一期預告:《SpringBoot+MyBatis整合Redis二級緩存實戰》——我們將深入探討如何構建高性能分布式緩存方案。