sql 片段复用
MyBatis 提供 <sql> 和 <include> 标签实现 SQL 片段的提取与引用,避免在多个 Statement 中重复编写相同 SQL。
基本语法
定义 SQL 片段:
XML
<sql id="baseColumns">
id, name, age, email, create_time
</sql>
引用 SQL 片段:
XML
<select id="findAll" resultType="User">
SELECT <include refid="baseColumns"/> FROM user
</select>
列定义复用
最常见场景是提取字段列表:
XML
<sql id="userColumns">
u.id, u.name, u.age, u.email, u.status,
u.create_time, u.update_time
</sql>
<select id="findById" resultType="User">
SELECT <include refid="userColumns"/> FROM user u WHERE u.id = #{id}
</select>
<select id="findByPage" resultType="User">
SELECT <include refid="userColumns"/>
FROM user u
<where>
<if test="status != null">u.status = #{status}</if>
</where>
LIMIT #{offset}, #{limit}
</select>
WHERE 条件复用
公共查询条件可提取复用:
XML
<sql id="statusCondition">
AND status != 'DELETED'
</sql>
<select id="findActive" resultType="User">
SELECT * FROM user
<where>
<include refid="statusCondition"/>
<if test="age != null">AND age >= #{age}</if>
</where>
</select>
跨 Mapper 复用
SQL 片段支持跨文件引用,使用 namespace 前缀:
XML
<!-- BaseMapper.xml -->
<sql id="baseQuery">
SELECT id, name, age FROM user WHERE status = 'ACTIVE'
</sql>
<!-- UserMapper.xml -->
<select id="findActiveUsers" resultType="User">
<include refid="com.example.mapper.BaseMapper.baseQuery"/>
<if test="name != null">AND name LIKE CONCAT('%', #{name}, '%')</if>
</select>
跨 Mapper 引用时,refid 格式为
namespace.sqlId。
动态片段
SQL 片段中可包含动态标签,引用时传入参数:
XML
<sql id="orderByClause">
<if test="sortField != null">
ORDER BY ${sortField} ${sortDirection}
</if>
</sql>
<select id="findWithSort" resultType="User">
SELECT * FROM user
<where>
<if test="name != null">name LIKE CONCAT('%', #{name}, '%')</if>
</where>
<include refid="orderByClause"/>
</select>
JOIN 语句复用
多表关联查询的 JOIN 部分也可提取:
XML
<sql id="userRoleJoin">
JOIN user_role ur ON u.id = ur.user_id
JOIN role r ON ur.role_id = r.id
</sql>
<select id="findUserWithRole" resultType="UserVO">
SELECT u.id, u.name, r.name as role_name
FROM user u
<include refid="userRoleJoin"/>
WHERE u.status = 'ACTIVE'
</select>
注意事项
<include>是纯文本替换,不参与 SQL 注入防护,${}变量在 include 中直接拼接<sql>内部可包含动态标签(if/where 等),但<include>只负责静态引用- 跨 Mapper 引用时 namespace 必须与
<mapper namespace="...">一致 - 修改
<sql>内容会影响所有引用处,变更需谨慎
要点总结
<sql>提取公共 SQL 片段,<include refid="...">引用,减少重复代码- 适用于列定义、WHERE 条件、JOIN、ORDER BY 等场景
- 支持跨 Mapper 引用,refid 格式为
namespace.sqlId - SQL 片段可包含动态标签,引用时仍是静态文本替换
- 修改片段影响全局引用处,需评估影响范围
📝 发现内容有误?点击此处直接编辑