一、sql语句优化
减少使用
SELECT *
:仅查询所需字段,降低数据传输量,sql
标签和include refid
配合使用使用
<if>
、<choose>
标签动态拼接条件,减少无效条件带来的性能损耗避免
<foreach>
标签生成过长的IN列表,若数据量过大可分批处理 (Oracle 和 MySQL 对 IN 子句中的元素数量确实有一定的限制)避免循环单条插入/更新:使用
<foreach>
标签生成批量SQL(如INSERT INTO ... VALUES (v1),(v2)
),合并多次操作为单次提交,减少与数据库的交互次数
二、缓存策略优化
我们知道,MyBatis为了增加查询的性能,提供了二级缓存架构,一级缓存和二级缓存。一级缓存是SqlSession级别,默认开启的;二级缓存是Mapper级别,默认关闭的,二级缓存可以实现跨会话。
在SpringBoot项目中,开启二级缓存的方法是:
- 在application.properties文件配置
mybatis.configuration.cache-enabled=true
- 具体的Mapper接口上添加
@CacheNamespace
注解 - PO实体类实现Serializable接口
<p style="color: red">MyBatis不推荐使用二级缓存</p>
因为它是Mapper级别,以namespace为单位,不同namespace下的操作互不影响。
一级缓存(SqlSession级别)
在SpringBoot项目中,集成的MyBatis默认每次执行SQL语句时,都会创建一个新的SqlSession,只有将当前方法开启事务,加上@Transactional
注解,一级缓存才会生效。
二级缓存(Mapper级别)
由于二级缓存可以实现跨会话,比较适合不会轻易修改但又是热点数据的缓存场景。
三级缓存
因为一级缓存仅在单个SqlSession内有效,二级缓存虽然可以多个SqlSession间共享,但存在缓存一致性的问题。
比如分布式系统,需要在二级缓存的基础上,增加一层更高效的缓存:三级缓存,需要集成外部缓存Redis实现。
需要根据业务场景和缓存特性,结合起来使用。
三、分页性能优化
使用MyBatis-Plus的PaginationInterceptor
或PageHelper插件,生成带LIMIT
的SQL,避免全量数据加载到内存,但需要注意避免深分页。
PageHelper.startPage(int pageNum, int pageSize, boolean count)
count
设为false时,在不需要总记录数的场景下,可以通过该操作减少一次数据库交互。
当原分页查询涉及多表关联或复杂逻辑时,需要重写分页插件的COUNT逻辑:在Mapper接口中添加_COUNT
后缀方法,简化统计逻辑。
<!-- 原分页查询 -->
<select id="selectByCondition" resultMap="BaseResultMap">
SELECT a.*, b.field
FROM table_a a
LEFT JOIN table_b b ON a.id = b.aid
WHERE a.status = #{status}
</select>
<!-- 自定义COUNT查询(仅统计主表) -->
<select id="selectByCondition_COUNT" resultType="Long">
SELECT COUNT(DISTINCT a.id)
FROM table_a a
WHERE a.status = #{status} <!-- 仅保留主表条件 -->
</select>
四、框架配置优化
使用数据库连接池,合理配置参数。
控制结果集的映射行为。
集成MyBatis监控工具Druid帮助分析SQL性能和识别慢SQL。