Mybatis基础操作

一、设置日志

mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

在Mybatis当中我们可以借助⽇志, 查看到sql语句的执⾏、执⾏传递的参数以及执⾏结果

二、XML 映射 SQL

在 MyBatis 中,你可以选择两种主要方式来编写 SQL 映射:使用 XML 映射文件或者使用 Java 注解。这两种方法各有优缺点,适用于不同的场景。以下是这两种方法的详细比较:

XML 映射是 MyBatis 最传统也是最灵活的配置方式。它将 SQL 语句和 Java 接口分离,使得 SQL 语句更易于管理和优化。

优点:
  • 集中管理:XML 文件可以集中管理 SQL 语句,易于维护和查阅。
  • 支持动态 SQL :XML 方式支持更为复杂的动态 SQL 语句,如条件语句(<if>)、循环语句(<foreach>)等,这些可以使 SQL 根据不同条件灵活生成。
  • 易于版本控制:作为文件的一部分,XML 映射可以轻松地纳入版本控制系统中。
缺点:
  • 间接性:代码与 SQL 分离,可能导致开发中来回查找对应 SQL 语句,降低开发效率。
  • 冗余:可能需要为每一个 SQL 语句编写大量的 XML 配置代码

三、注解 映射 SQL

注解方式是 MyBatis 在较新版本中引入的,它将 SQL 语句直接写在 Mapper 接口的方法上,减少了配置的复杂性。

优点:
  • 直接性:SQL 语句与 Java 方法紧密绑定,易于阅读和修改。
  • 简洁:减少了 XML 的冗余配置,使得项目结构更为简洁。
缺点:
  • 有限的动态 SQL 支持 :虽然注解支持基本的动态 SQL,如 @Select@Insert 等,但对于复杂的动态 SQL,如条件判断、循环等支持不如 XML 方式。

  • 可扩展性有限 :对于非常复杂的 SQL,注解方式可能显得力不从心。

    java 复制代码
    public interface UserMapper {
        @Select("SELECT * FROM users WHERE id = #{id}")
        User selectUserById(int id);
    }

四、参数传递

1)一个参数

如果 SQL 语句只需要一个参数,你可以直接在 mapper 接口的方法中传递这个参数。MyBatis 会自动将它识别为 SQL 语句中的参数。

java 复制代码
public interface UserMapper {
    User selectUserById(int id);
}

Mapper XML

XML 复制代码
<select id="selectUserById" parameterType="int" resultType="com.example.mybatisdemo.model.User">
    SELECT * FROM users WHERE id = #{id}
</select>

在这个例子中,#{id} 是一个占位符,用于在执行时替换成方法 selectUserById(int id) 中的参数。

2)多个参数

当方法中有多个参数时,MyBatis 提供了几种处理方式:

  • @Param 注解 :最常用的方式,可以给参数命名,然后在 SQL 语句中引用这些名称、Mapper 接口

    java 复制代码
    public interface UserMapper {
        User findUserByNameAndEmail(@Param("name") String name, @Param("email") String email);
    }

    Mapper XML

    XML 复制代码
    <select id="findUserByNameAndEmail" resultType="com.example.mybatisdemo.model.User">
        SELECT * FROM users WHERE name = #{name} AND email = #{email}
    </select>

    使用 @Param 注解可以明确指定 SQL 语句中参数的名称,这样即使参数的顺序改变,也不会影响 SQL 语句的执行

3) 返回主键

在 MyBatis 中,将操作结果的自动生成的主键(如数据库自增主键)返回到应用程序中是一个常见需求。这通常在执行插入(INSERT)操作时使用。MyBatis 提供了几种方式来处理自动生成的主键,并将其返回。

a) 使用 XML 映射

当你使用 XML 映射文件定义 SQL 语句时,可以通过 useGeneratedKeyskeyProperty 属性来指定如何返回自动生成的主键。

示例:

假设你有一个名为 users 的表,其中 id 字段是自增主键。

XML 复制代码
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO users (name, email) VALUES (#{name}, #{email})
</insert>

在这个例子中:

  • useGeneratedKeys="true" 告诉 MyBatis 使用 JDBC 的 getGeneratedKeys() 方法来检索由数据库自动生成的键。
  • keyProperty="id" 指定 MyBatis 应将获取的键值设置到哪个属性上。在本例中,它将设置到 User 对象的 id 属性上。
b) 使用注解

当你使用注解来配置 MyBatis 映射时,可以使用 @Options 注解来指定如何处理自动生成的键。

Mapper 接口方法:

java 复制代码
public interface UserMapper {
    @Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insertUser(User user);
}

这里的 @Options 注解具有与 XML 相同的属性:

  • useGeneratedKeys = true 这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内 部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递增字 段),默认值:false
  • keyProperty = "id" 指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值或 insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置(unset)

五、SELECT 查找

在 MyBatis 中,字段映射的默认行为是按照属性名和数据库字段名进行匹配。如果 Java 对象的属性名与数据库表的字段名不一致,你需要显式地指定这种映射关系,以确保正确的数据赋值

1. 起别名 (Alias)

在 SQL 查询中直接为字段起别名,使其与 Java 对象的属性名匹配。这是一种非常简单且直接的方式,适用于简单的场景。

示例:

假设数据库字段名为 emp_name,而 Java 对象的属性名为 name,可以在 SQL 语句中直接为 emp_name 起别名为 name

sql 复制代码
SELECT emp_id as id, emp_name as name, emp_email as email FROM employees

使用这种方法,MyBatis 在映射结果到 Java 对象时会自动将 name 列的值赋给 name 属性。

2. 结果映射 (Result Mapping)

使用 MyBatis 的 resultMap 元素来定义字段映射关系。这种方式提供了高度的灵活性和控制力,适用于复杂的数据结构和关系。

示例:

在 MyBatis 映射文件中使用 resultMap 来定义字段与属性的映射关系:

XML 复制代码
<mapper namespace="com.example.mapper.EmployeeMapper">
    <resultMap id="EmployeeMap" type="Employee">
        <result property="id" column="emp_id"/>
        <result property="name" column="emp_name"/>
        <result property="email" column="emp_email"/>
    </resultMap>

    <select id="selectEmployee" resultMap="EmployeeMap">
        SELECT emp_id, emp_name, emp_email FROM employees
    </select>
</mapper>

这个 resultMap 显式地告诉 MyBatis 如何将数据库字段映射到 Java 对象的属性。

3. 开启驼峰命名 (Camel Case Mapping)

通常数据库列使⽤蛇形命名法进⾏命名(下划线分割各个单词), ⽽ Java 属性⼀般遵循驼峰命名法约定. 为了在这两种命名⽅式之间启⽤⾃动映射,需要将 mapUnderscoreToCamelCase 设置为 true。

XML 复制代码
mybatis:
 configuration:
  map-underscore-to-camel-case: true #配置驼峰⾃动转换

开启这个配置后,MyBatis 会自动将诸如 emp_name 的字段名映射为 empName 的 Java 属性。这样,你不需要在每个 SQL 语句中为字段起别名,也不需要在每个映射中定义 resultMap

六、#{} 和 ${}

在 MyBatis 中,#{}${} 是两种基本的参数占位符,用于在 SQL 语句中插入参数值,但它们的工作方式和用途有明显的区别:

1. #{} (Prepared Statement 占位符)

#{} 是用来创建预处理语句 (Prepared Statement) 的参数占位符。当你使用 #{} 时,MyBatis 会使用 JDBC 的 PreparedStatement 功能,这意味着参数值在传递给数据库之前会进行适当的转义,从而防止 SQL 注入攻击。这是处理用户输入或不可信数据时推荐的做法。

示例:
sql 复制代码
SELECT * FROM users WHERE id = #{id}

在这里,#{id} 会被替换为一个参数标记,如 ?,并且 id 的值会在执行时被安全地绑定到这个问号上。如果 id5,那么实际执行的 SQL 会是:

sql 复制代码
SELECT * FROM users WHERE id = ?

并且 5 作为参数传递,这样可以防止 SQL 注入。

2. ${} (文本替换占位符)

${} 用于直接将参数值插入 SQL 语句中。这种方式可以用于动态更改表名、列名或者是 SQL 语句的其它部分,而不仅仅是值。使用 ${} 时,必须非常小心,因为它不会对参数值进行任何处理或转义,从而有可能导致 SQL 注入风险。

sql 复制代码
SELECT * FROM ${tableName} WHERE id = ${id}

如果 tableNameusers,而 id5,那么生成的 SQL 将直接是:

sql 复制代码
SELECT * FROM users WHERE id = 5

这种方式使得你可以灵活地构建 SQL 语句,但如果 tableNameid 来自于用户输入或其他不可信的来源,则可能会带来安全风险。

选择使用哪一个
  • 当你需要插入安全的、转义后的数据值时,使用 #{}
  • 当你需要在 SQL 语句中动态插入表名、列名或其他不会改变 SQL 逻辑的元素时,可以使用 ${},但必须非常小心确保这些值是安全的,避免 SQL 注入。

通常,除非绝对必要,建议尽量避免使用 ${} 来避免潜在的安全问题。使用 #{} 可以利用 PreparedStatement 的优势,有效防止 SQL 注入,是更安全的选择。

${}的必要性
1.排序
java 复制代码
@Select("select id, username, age, gender, phone, delete_flag, create_time, 
update_time " +
 "from userinfo order by id ${sort} ")
List<UserInfo> queryAllUserBySort(String sort);

使⽤ ${sort} 可以实现排序查询, ⽽使⽤ #{sort} 就不能实现排序查询了. 注意: 此处 sort 参数为String类型, 但是SQL语句中, 排序规则是不需要加引号 '' 的, 所以此时的 ${sort} 也不加引号

当使⽤ #{sort} 查询时, asc 前后⾃动给加了引号, 导致 sql 错误 #{} 会根据参数类型判断是否拼接引号 '' 如果参数类型为String, 就会加上 引号

除此之外, 还有表名作为参数时, 也只能使⽤ ${}

2.like 查询

在 MyBatis 中使用 #{} 对于大多数情况都是正常工作的,但在使用 LIKE 语句时,可能会遇到问题。这是因为 #{} 在转换过程中会将输入视为字面值,并且会自动在值周围添加单引号。这在 LIKE 查询中通常不是预期的行为,因为通配符(如 %)需要与字段值直接相连。

当你使用 LIKE 并希望包含通配符时,如下

sql 复制代码
SELECT * FROM users WHERE name LIKE '%#{name}%'

MyBatis 会处理这个语句并将其转换为:

sql 复制代码
SELECT * FROM users WHERE name LIKE '%\'someName\'%'

这里的单引号是自动添加的,导致 SQL 语句错误,因为 SQL 不期望在 %someName 之间有额外的单引号。

为了正确使用 LIKE,你应该让 MyBatis 在不添加额外单引号的情况下处理变量。有两种主要方法可以实现:

使用 CONCAT 函数

你可以使用 SQL 的 CONCAT 函数来确保通配符和变量被正确组合,而不是将它们作为字符串字面值直接插入。这在大多数数据库中都有效。

sql 复制代码
SELECT * FROM users WHERE name LIKE CONCAT('%', #{name}, '%')
安全性考虑

尽管 ${} 在这种情况下是必要的,但它引入了潜在的 SQL 注入风险。为了安全地使用 ${},你需要确保:

  1. 输入验证 :对传入的列名和排序方向进行严格验证,确保它们是预定义的有效值。例如,你可以在应用层或服务层检查 orderByColumn 是否确实是数据库中的列名,orderDir 是否仅为 "ASC" 或 "DESC"。

  2. 使用白名单:仅允许特定的、安全的字段名和排序方向,可以通过在服务层设置一个白名单来实现。

通过这种方式,尽管使用了 ${},但通过严格的输入验证和白名单策略,可以最大程度地减少 SQL 注入的风险,使得动态排序既灵活又安全。这种方法适用于需要高度动态性的 SQL 操作,如动态排序、动态查询字段等场景。

相关推荐
何遇mirror1 小时前
Spring Boot快速入门详解
spring boot
不惑_2 小时前
缓存技巧 · Spring Cache && Caffeine 高性能缓存库
java·spring·缓存
bug菌¹3 小时前
滚雪球学SpringCloud[6.3讲]: 分布式日志管理与分析
分布式·spring·spring cloud
2401_857638033 小时前
Spring Boot框架在高校心理辅导中的实践
java·spring boot·后端
潘多编程3 小时前
Spring Boot和AOP将API输入输出数据存入数据库
数据库·spring boot·后端
DeepCoder_Mx4 小时前
Spring Boot 学习之路 -- 基础认知
spring boot·后端
ChinaRainbowSea4 小时前
十五,Spring Boot 整合连接数据库(详细配置)
java·数据库·spring boot·后端·spring·web
张某布响丸辣5 小时前
Spring Security 详解:保护Java应用的强大盾牌
java·后端·spring
我不会画饼鸭5 小时前
springboot 控制器
java·spring boot·后端