当前位置: 首页 > news >正文

SSM从入门到实战:2.5 SQL映射文件与动态SQL

👋 大家好,我是 阿问学长!专注于分享优质开源项目解析、毕业设计项目指导支持、幼小初高教辅资料推荐等,欢迎关注交流!🚀

12-SQL映射文件与动态SQL

📖 本文概述

本文是SSM框架系列MyBatis进阶篇的第二篇,将深入探讨SQL映射文件的编写技巧和动态SQL的使用方法。通过丰富的示例和最佳实践,帮助读者掌握MyBatis中最核心的功能之一。

🎯 学习目标

  • 深入理解SQL映射文件的结构和元素
  • 掌握结果映射(ResultMap)的高级用法
  • 学会编写各种类型的动态SQL
  • 了解SQL片段的复用技巧
  • 掌握复杂查询和关联映射的实现

1. SQL映射文件概述

1.1 映射文件的基本结构

SQL映射文件是MyBatis的核心,它定义了SQL语句和Java对象之间的映射关系。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.mapper.UserMapper"><!-- 结果映射 --><resultMap id="BaseResultMap" type="User"><!-- 主键映射 --><id column="id" property="id" jdbcType="BIGINT"/><!-- 普通字段映射 --><result column="username" property="username" jdbcType="VARCHAR"/><result column="email" property="email" jdbcType="VARCHAR"/></resultMap><!-- SQL片段 --><sql id="Base_Column_List">id, username, email, password, age, create_time, update_time</sql><!-- 查询语句 --><select id="findById" parameterType="long" resultMap="BaseResultMap">SELECT <include refid="Base_Column_List"/>FROM usersWHERE id = #{id}</select><!-- 插入语句 --><insert id="insert" parameterType="User">INSERT INTO users (username, email, password, age)VALUES (#{username}, #{email}, #{password}, #{age})</insert><!-- 更新语句 --><update id="update" parameterType="User">UPDATE usersSET username = #{username}, email = #{email}WHERE id = #{id}</update><!-- 删除语句 --><delete id="deleteById" parameterType="long">DELETE FROM users WHERE id = #{id}</delete></mapper>

1.2 映射文件的主要元素

  • mapper:根元素,包含namespace属性
  • resultMap:结果映射,定义如何将查询结果映射到Java对象
  • sql:可重用的SQL片段
  • select:查询语句
  • insert:插入语句
  • update:更新语句
  • delete:删除语句

2. 结果映射(ResultMap)详解

2.1 基础结果映射

<!-- 基础结果映射 -->
<resultMap id="UserResultMap" type="com.example.entity.User"><!-- id元素:主键字段映射 --><id column="user_id" property="id" jdbcType="BIGINT"/><!-- result元素:普通字段映射 --><result column="user_name" property="username" jdbcType="VARCHAR"/><result column="user_email" property="email" jdbcType="VARCHAR"/><result column="user_age" property="age" jdbcType="INTEGER"/><result column="create_time" property="createTime" jdbcType="TIMESTAMP"/><result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
</resultMap>

2.2 复杂类型映射

<!-- 包含复杂类型的结果映射 -->
<resultMap id="UserWithProfileResultMap" type="User"><id column="id" property="id"/><result column="username" property="username"/><result column="email" property="email"/><!-- association:一对一关联映射 --><association property="profile" javaType="UserProfile"><id column="profile_id" property="id"/><result column="real_name" property="realName"/><result column="phone" property="phone"/><result column="address" property="address"/></association><!-- collection:一对多关联映射 --><collection property="roles" ofType="Role"><id column="role_id" property="id"/><result column="role_name" property="roleName"/><result column="role_description" property="description"/></collection>
</resultMap>

2.3 继承结果映射

<!-- 基础结果映射 -->
<resultMap id="BaseUserResultMap" type="User"><id column="id" property="id"/><result column="username" property="username"/><result column="email" property="email"/><result column="create_time" property="createTime"/>
</resultMap><!-- 继承基础映射并扩展 -->
<resultMap id="ExtendedUserResultMap" type="User" extends="BaseUserResultMap"><result column="last_login_time" property="lastLoginTime"/><result column="login_count" property="loginCount"/><!-- 添加关联映射 --><association property="profile" javaType="UserProfile"><id column="profile_id" property="id"/><result column="real_name" property="realName"/></association>
</resultMap>

2.4 自动映射配置

<!-- 开启自动映射 -->
<resultMap id="AutoMappingResultMap" type="User" autoMapping="true"><!-- 只需要配置特殊的映射关系 --><id column="user_id" property="id"/><!-- 其他字段会自动映射(如果字段名和属性名匹配) -->
</resultMap>

3. 动态SQL详解

3.1 if标签

if标签是最常用的动态SQL标签,用于条件判断。

<!-- 基础if用法 -->
<select id="findUsersByCondition" parameterType="User" resultMap="BaseResultMap">SELECT * FROM usersWHERE 1=1<if test="username != null and username != ''">AND username = #{username}</if><if test="email != null and email != ''">AND email = #{email}</if><if test="age != null">AND age = #{age}</if><if test="createTime != null">AND create_time >= #{createTime}</if>
</select><!-- 复杂条件判断 -->
<select id="findUsersWithComplexCondition" parameterType="map" resultMap="BaseResultMap">SELECT * FROM usersWHERE 1=1<if test="keyword != null and keyword != ''">AND (username LIKE CONCAT('%', #{keyword}, '%') OR email LIKE CONCAT('%', #{keyword}, '%'))</if><if test="ageRange != null"><if test="ageRange.min != null">AND age >= #{ageRange.min}</if><if test="ageRange.max != null">AND age <= #{ageRange.max}</if></if><if test="roles != null and roles.size() > 0">AND id IN (SELECT user_id FROM user_roles WHERE role_id IN<foreach collection="roles" item="roleId" open="(" separator="," close=")">#{roleId}</foreach>)</if>
</select>

3.2 where标签

where标签可以智能地处理WHERE子句,自动去除多余的AND或OR。

<select id="findUsersByConditionWithWhere" parameterType="User" resultMap="BaseResultMap">SELECT * FROM users<where><if test="username != null and username != ''">AND username = #{username}</if><if test="email != null and email != ''">AND email = #{email}</if><if test="age != null">AND age = #{age}</if><if test="status != null">AND status = #{status}</if></where>ORDER BY create_time DESC
</select>

3.3 set标签

set标签用于动态更新语句,自动处理逗号分隔符。

<update id="updateUserSelective" parameterType="User">UPDATE users<set><if test="username != null and username != ''">username = #{username},</if><if test="email != null and email != ''">email = #{email},</if><if test="password != null and password != ''">password = #{password},</if><if test="age != null">age = #{age},</if><if test="status != null">status = #{status},</if>update_time = CURRENT_TIMESTAMP</set>WHERE id = #{id}
</update>

3.4 choose、when、otherwise标签

类似于Java中的switch语句,用于多分支条件判断。

<select id="findUsersByType" parameterType="map" resultMap="BaseResultMap">SELECT * FROM usersWHERE 1=1<choose><when test="type == 'active'">AND status = 'ACTIVE' AND last_login_time > DATE_SUB(NOW(), INTERVAL 30 DAY)</when><when test="type == 'inactive'">AND status = 'ACTIVE' AND last_login_time <= DATE_SUB(NOW(), INTERVAL 30 DAY)</when><when test="type == 'disabled'">AND status = 'DISABLED'</when><otherwise>AND status = 'ACTIVE'</otherwise></choose><if test="orderBy != null"><choose><when test="orderBy == 'username'">ORDER BY username</when><when test="orderBy == 'createTime'">ORDER BY create_time DESC</when><when test="orderBy == 'lastLogin'">ORDER BY last_login_time DESC</when><otherwise>ORDER BY id</otherwise></choose></if>
</select>

3.5 foreach标签

foreach标签用于遍历集合,常用于IN查询和批量操作。

<!-- IN查询 -->
<select id="findUsersByIds" parameterType="list" resultMap="BaseResultMap">SELECT * FROM usersWHERE id IN<foreach collection="list" item="id" open="(" separator="," close=")">#{id}</foreach>
</select><!-- 批量插入 -->
<insert id="batchInsertUsers" parameterType="list">INSERT INTO users (username, email, password, age)VALUES<foreach collection="list" item="user" separator=",">(#{user.username}, #{user.email}, #{user.password}, #{user.age})</foreach>
</insert><!-- 批量更新(MySQL特有语法) -->
<update id="batchUpdateUsers" parameterType="list"><foreach collection="list" item="user" separator=";">UPDATE usersSET username = #{user.username}, email = #{user.email}WHERE id = #{user.id}</foreach>
</update><!-- 复杂的foreach用法 -->
<select id="findUsersByMultipleConditions" parameterType="map" resultMap="BaseResultMap">SELECT * FROM usersWHERE 1=1<if test="userIds != null and userIds.size() > 0">AND id IN<foreach collection="userIds" item="userId" open="(" separator="," close=")">#{userId}</foreach></if><if test="conditions != null and conditions.size() > 0">AND (<foreach collection="conditions" item="condition" separator=" OR ">(username LIKE CONCAT('%', #{condition.keyword}, '%') AND age BETWEEN #{condition.minAge} AND #{condition.maxAge})</foreach>)</if>
</select>

3.6 trim标签

trim标签是更通用的标签,可以自定义前缀、后缀和分隔符的处理。

<!-- 使用trim实现where功能 -->
<select id="findUsersWithTrim" parameterType="User" resultMap="BaseResultMap">SELECT * FROM users<trim prefix="WHERE" prefixOverrides="AND |OR "><if test="username != null">AND username = #{username}</if><if test="email != null">AND email = #{email}</if><if test="age != null">AND age = #{age}</if></trim>
</select><!-- 使用trim实现set功能 -->
<update id="updateUserWithTrim" parameterType="User">UPDATE users<trim prefix="SET" suffixOverrides=","><if test="username != null">username = #{username},</if><if test="email != null">email = #{email},</if><if test="age != null">age = #{age},</if></trim>WHERE id = #{id}
</update><!-- 复杂的trim用法 -->
<insert id="insertUserWithTrim" parameterType="User">INSERT INTO users<trim prefix="(" suffix=")" suffixOverrides=","><if test="username != null">username,</if><if test="email != null">email,</if><if test="password != null">password,</if><if test="age != null">age,</if></trim><trim prefix="VALUES (" suffix=")" suffixOverrides=","><if test="username != null">#{username},</if><if test="email != null">#{email},</if><if test="password != null">#{password},</if><if test="age != null">#{age},</if></trim>
</insert>

4. SQL片段复用

4.1 基础SQL片段

<!-- 定义可重用的SQL片段 -->
<sql id="Base_Column_List">id, username, email, password, age, create_time, update_time
</sql><sql id="User_Where_Clause"><where><if test="username != null and username != ''">AND username = #{username}</if><if test="email != null and email != ''">AND email = #{email}</if><if test="age != null">AND age = #{age}</if><if test="status != null">AND status = #{status}</if></where>
</sql><!-- 使用SQL片段 -->
<select id="findUsers" parameterType="User" resultMap="BaseResultMap">SELECT <include refid="Base_Column_List"/>FROM users<include refid="User_Where_Clause"/>ORDER BY create_time DESC
</select><select id="countUsers" parameterType="User" resultType="long">SELECT COUNT(*)FROM users<include refid="User_Where_Clause"/>
</select>

4.2 带参数的SQL片段

<!-- 带参数的SQL片段 -->
<sql id="orderByClause"><if test="${orderBy} != null and ${orderBy} != ''">ORDER BY ${orderBy}<if test="${orderDirection} != null and ${orderDirection} != ''">${orderDirection}</if></if>
</sql><!-- 使用带参数的SQL片段 -->
<select id="findUsersWithOrder" parameterType="map" resultMap="BaseResultMap">SELECT <include refid="Base_Column_List"/>FROM users<include refid="User_Where_Clause"/><include refid="orderByClause"><property name="orderBy" value="orderBy"/><property name="orderDirection" value="orderDirection"/></include>
</select>

4.3 复杂SQL片段组合

<!-- 分页查询片段 -->
<sql id="limitClause"><if test="offset != null and limit != null">LIMIT #{offset}, #{limit}</if>
</sql><!-- 连接查询片段 -->
<sql id="userRoleJoin">LEFT JOIN user_roles ur ON u.id = ur.user_idLEFT JOIN roles r ON ur.role_id = r.id
</sql><!-- 复杂查询组合 -->
<select id="findUsersWithRolesAndPaging" parameterType="map" resultMap="UserWithRolesResultMap">SELECT u.id, u.username, u.email, u.create_time,r.id as role_id, r.role_name, r.description as role_descriptionFROM users u<include refid="userRoleJoin"/><where><if test="username != null and username != ''">AND u.username LIKE CONCAT('%', #{username}, '%')</if><if test="roleName != null and roleName != ''">AND r.role_name = #{roleName}</if><if test="startDate != null">AND u.create_time >= #{startDate}</if><if test="endDate != null">AND u.create_time <= #{endDate}</if></where>ORDER BY u.create_time DESC<include refid="limitClause"/>
</select>

5. 高级映射技巧

5.1 嵌套查询

<!-- 用户结果映射,包含延迟加载的角色信息 -->
<resultMap id="UserWithLazyRolesResultMap" type="User"><id column="id" property="id"/><result column="username" property="username"/><result column="email" property="email"/><!-- 嵌套查询,延迟加载角色信息 --><collection property="roles" ofType="Role" select="findRolesByUserId" column="id"fetchType="lazy"/>
</resultMap><!-- 查询用户的角色 -->
<select id="findRolesByUserId" parameterType="long" resultType="Role">SELECT r.id, r.role_name as roleName, r.descriptionFROM roles rINNER JOIN user_roles ur ON r.id = ur.role_idWHERE ur.user_id = #{userId}
</select><!-- 查询用户(角色信息会延迟加载) -->
<select id="findUserWithLazyRoles" parameterType="long" resultMap="UserWithLazyRolesResultMap">SELECT id, username, email, create_timeFROM usersWHERE id = #{id}
</select>

5.2 嵌套结果映射

<!-- 嵌套结果映射,一次查询获取所有数据 -->
<resultMap id="UserWithRolesNestedResultMap" type="User"><id column="user_id" property="id"/><result column="username" property="username"/><result column="email" property="email"/><result column="create_time" property="createTime"/><!-- 嵌套结果映射 --><collection property="roles" ofType="Role"><id column="role_id" property="id"/><result column="role_name" property="roleName"/><result column="role_description" property="description"/><result column="role_create_time" property="createTime"/></collection>
</resultMap><!-- 一次查询获取用户和角色信息 -->
<select id="findUserWithRolesNested" parameterType="long" resultMap="UserWithRolesNestedResultMap">SELECT u.id as user_id,u.username,u.email,u.create_time,r.id as role_id,r.role_name,r.description as role_description,r.create_time as role_create_timeFROM users uLEFT JOIN user_roles ur ON u.id = ur.user_idLEFT JOIN roles r ON ur.role_id = r.idWHERE u.id = #{id}
</select>

6. 小结

本文深入介绍了MyBatis SQL映射文件和动态SQL的核心功能:

  1. 结果映射:基础映射、复杂类型映射、继承映射
  2. 动态SQL标签:if、where、set、choose、foreach、trim
  3. SQL片段复用:提高代码复用性和维护性
  4. 高级映射:嵌套查询和嵌套结果映射

掌握这些技能可以:

  • 编写灵活的动态SQL语句
  • 处理复杂的查询需求
  • 优化SQL性能和代码结构
  • 实现高效的对象关系映射

🔗 下一篇预告

下一篇文章将探讨MyBatis缓存机制与性能优化,学习如何使用MyBatis的一级缓存和二级缓存来提升应用性能。


相关文章:

  • 上一篇:MyBatis配置文件详解
  • 下一篇:MyBatis缓存机制与性能优化
  • 返回目录
http://www.dtcms.com/a/344186.html

相关文章:

  • C#中的LOCK
  • 关于 WebDriver Manager (自动管理浏览器驱动)
  • 第二阶段Winform-4:MDI窗口,布局控件,分页
  • 3.4 缩略词抽取
  • 企业级 AI 智能体安全落地指南:从攻击面分析到纵深防御体系构建
  • FileCodeBox 文件快递柜 一键部署
  • 获取后台返回的错误码
  • 如何使用命令行将DOCX文档转换为PDF格式?
  • Linux应用软件编程---网络编程1(目的、网络协议、网络配置、UDP编程流程)
  • Matplotlib 可视化大师系列(八):综合篇 - 在一张图中组合多种图表类型
  • 2.4G和5G位图说明列表,0xff也只是1-8号信道而已
  • QT QImage 判断图像无效
  • 高通平台WIFI学习-- 基于高通基线如何替换移植英飞凌WIFI芯片代码
  • mysql编程(简单了解)
  • 【Android】include复用布局 在xml中静态添加Fragment
  • 计数组合学7.20(平面分拆与RSK算法)
  • [测试技术] 接口测试中如何高效开展幂等性测试
  • pthon实现bilibili缓存视频音频分离
  • Redis内存碎片深度解析:成因、检测与治理实战指南
  • K8s存储类(StorageClass)设计与Ceph集成实战
  • 为什么应用会突然耗尽所有数据库连接
  • 智慧清洁时代来临:有鹿机器人重新定义城市清洁标准
  • 【数据结构】B 树——高度近似可”独木成林“的榕树——详细解说与其 C 代码实现
  • python selenium+pytest webUI自动化基础框架
  • 去中心化身份--改变格局的关键
  • 图数据库(neo4j)基础: 分类/标签 节点 关系 属性
  • 整数规划学习总结
  • 为什么给数据表加了索引,写入速度反而变慢了
  • 数据库原理及应用_数据库基础_第2章关系数据库标准语言SQL_数据查询(3)连接查询
  • 基于Python/django的仓库库存管理系统#基于Python的仓库管理系统#基django的J进销存管理系统