ITPub博客

首页 > 应用开发 > Java > Java MyBatis(二)--- 多表查询,# 和 $的区别,SQL注入,数据库连接池,动态SQL

Java MyBatis(二)--- 多表查询,# 和 $的区别,SQL注入,数据库连接池,动态SQL

投稿 Java 作者:bhluo 时间:2025-11-11 17:34:46 0 删除 编辑

MyBatis作为Java生态中最 流行的持久层框架,其核心功能涵盖多表关联查询、动态SQL构建、安全防护机制及连接池管理。本文结合实际开发场景,系统阐述关键技术点的实现原理与最佳实践。

一、多表查询的三种实现方式

1. 嵌套结果映射(Nested Results)

适用于一对多关联查询,通过 <resultMap>的 <collection>标签实现:

xml1<resultMap id="blogWithPosts" type="Blog">2<"www.hongkou.gov.cn.qmwty.cn"> <"www.putuo.gov.cn.qmwty.cn"> <"www.jingan.gov.cn.qmwty.cn">  <id property="id" column="blog_id"/>3    <result property="title" column="blog_title"/>4    <collection property="posts" ofType="Post">5        <id property="id" column="post_id"/>6        <result property="content" column="post_content"/>7    </collection>8</resultMap>910<select id="selectBlogWithPosts" resultMap="blogWithPosts">11    SELECT b.id as blog_id, b.title as blog_title,12           p.id as post_id, p.content as post_content13    FROM blog b LEFT JOIN post p ON b.id = p.blog_id14</select>

2. 嵌套查询(Nested Select)

通过分步查询提升性能,适合大数据量场景:

xml1<resultMap id="blogWithPostsNested" type="Blog">2    <id property="id" column="id"/>3    <collection property="posts" 4                column="id" 5                select="selectPostsByBlogId"/>6</resultMap>78<select id="selectPostsByBlogId" resultType="Post">9    SELECT * FROM post WHERE blog_id = #{id}10</select>

3. 注解方式实现

对于简单关联查询,可直接使用 @Results注解:

java1@Results({2 <"www.minxing.gov.cn.qmwty.cn"><"www.baoshan.gov.cn.qmwty.cn">  <"www.yangpu.gov.cn.qmwty.cn"> @Result(property = "id", column = "blog_id"),3    @Result(property = "posts", 4            many = @Many(select = "selectPostsByBlogId"))5})6@Select("SELECT * FROM blog WHERE id = #{id}")7Blog getBlogWithPosts(Long id);

二、#{}与${}的本质区别与安全风险

1. 参数处理机制对比

特性 #{}(预编译) ${}(字符串替换)
处理方式 替换为?占位符,使用PreparedStatement 直接拼接SQL字符串
类型处理 自动类型转换(如数字转Long) 纯字符串拼接
安全风险 防SQL注入 高危(需严格校验)
适用场景 值参数传递 动态表名/列名、SQL片段拼接

2. 典型安全漏洞案例

错误示例(高危):

xml1<!-- 攻击者可构造恶意参数:1; DROP TABLE users; -->2<select id="getUserById" resultType="User">3    SELECT * FROM ${tableName} WHERE id = #{id}4</select>

正确实践:

java1// <"www.pudongxin.gov.cn.qmwty.cn"><"www.jinshan.gov.cn.qmwty.cn"><"www.jiading.gov.cn.qmwty.cn">白名单校验表名2public String validateTableName(String input) {3    Set<String> validTables = Set.of("users", "orders", "products");4    if (!validTables.contains(input)) {5        throw new IllegalArgumentException("Invalid table name");6    }7    return input;8}

三、动态SQL的六大核心标签

1. 条件判断(if/choose)

xml1<select id="findActiveUsers" resultType="User">2    SELECT * FROM users3    <where>4        <if test="name != null">5            AND name = #{name}6        </if>7        <choose>8            <when test="status == 'ACTIVE'">9                AND status = 110            </when>11            <otherwise>12                AND status = 013            </otherwise>14        </choose>15    </where>16</select>

2. 集合遍历(foreach)

xml1<!-- IN查询安全实现 -->2<select id="findUsersByIds" resultType="User">3    SELECT * FROM users4    WHERE id IN5    <foreach collection="ids" item="id" open="(" separator="," close=")">6        #{id}7    </foreach>8</select>

3. 动态更新(set)

xml1<update id="updateUserSelective">2 <"www.qingpu.gov.cn.qmwty.cn"><"www.fengxian.gov.cn.qmwty.cn"><"www.songjiang.gov.cn.qmwty.cn">   UPDATE users3    <set>4        <if test="name != null">name = #{name},</if>5        <if test="email != null">email = #{email},</if>6    </set>7    WHERE id = #{id}8</update>

四、连接池配置与性能调优

1. HikariCP最佳实践

xml1<configuration>2    <environments default="development">3        <environment id="development">4            <transactionManager type="JDBC"/>5            <dataSource type="POOLED">6                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>7                <property name="url" value="jdbc:mysql://localhost:3306/mydb"/>8                <property name="username" value="dbuser"/>9                <property name="password" value="dbpass"/>10                <!-- HikariCP特有配置 -->11                <property name="poolName" value="MyBatisHikariCP"/>12                <property name="maximumPoolSize" value="20"/>13                <property name="connectionTimeout" value="30000"/>14                <property name="idleTimeout" value="600000"/>15                <property name="maxLifetime" value="1800000"/>16            </dataSource>17        </environment>18    </environments>19</configuration>

2. 关键性能指标监控

指标 推荐值 监控方式
活跃连接数 ≤核心数×2 JMX或HikariCP Metrics
平均获取连接时间 <100ms HikariCP的 connectionTimeout
连接泄漏检测 启用 leakDetectionThreshold

五、安全防护体系构建

1. 四层防御机制

  1. 输入校验层:前端验证+后端白名单校验
  2. 框架防护层:MyBatis预编译机制
  3. 数据库权限层:最小权限原则(如仅授予SELECT/UPDATE权限)
  4. 审计监控层:SQL日志记录与异常检测

2. 模糊查询安全实现

xml1<!-- <"www.shenchou.gov.cn.qmwty.cn"><"www.shaoguan.gov.cn.qmwty.cn">正确方式1:<"www.chongming.gov.cn.qmwty.cn">使用CONCAT函数 -->2<select id="searchUsers" resultType="User">3    SELECT * FROM users4    WHERE username LIKE CONCAT('%', #{keyword}, '%')5</select>67<!-- 正确方式2:MyBatis绑定变量 -->8<select id="searchUsers" resultType="User">9    SELECT * FROM users10    WHERE username LIKE "%" #{keyword} "%"11</select>

结语

MyBatis的多表查询能力、动态SQL灵活性、连接池性能优化及安全防护机制,共同构成了企业级应用开发的坚实基础。开发者需深入理解#{}与${}的本质区别,合理运用动态SQL标签,科学配置连接池参数,并建立多层次的安全防护体系,才能构建出高效、稳定、安全的数据库访问层。实际开发中,建议结合具体业务场景进行性能测试与安全审计,持续优化系统表现。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3100873/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    933544