【Mybatis】常见面试题汇总 共56题

文章目录

  • [1. 介绍下MyBatis?](#1. 介绍下MyBatis?)
  • [2. MyBatis 框架的应用场景?](#2. MyBatis 框架的应用场景?)
  • [3. MyBatis 有哪些优点?](#3. MyBatis 有哪些优点?)
  • [4. MyBatis 有哪些缺点?](#4. MyBatis 有哪些缺点?)
  • [5. MyBatis 用到了哪些设计模式?](#5. MyBatis 用到了哪些设计模式?)
  • [6. MyBatis常用注解有哪些?](#6. MyBatis常用注解有哪些?)
  • [7. MyBatis 有哪些核心组件?](#7. MyBatis 有哪些核心组件?)
  • [8. MyBatis编程步骤是什么样的?](#8. MyBatis编程步骤是什么样的?)
  • [9. MyBatis 和JDBC有什么区别?](#9. MyBatis 和JDBC有什么区别?)
  • [10. MyBatis 中的缓存机制有啥用?](#10. MyBatis 中的缓存机制有啥用?)
  • [11. MyBatis 一级缓存和二级缓存的区别?](#11. MyBatis 一级缓存和二级缓存的区别?)
  • [12. MyBatis 一级缓存和二级缓存是什么数据结构?](#12. MyBatis 一级缓存和二级缓存是什么数据结构?)
  • [13. MyBatis 中的缓存有哪些实现类型?](#13. MyBatis 中的缓存有哪些实现类型?)
  • [14. MyBatis 默认会开启缓存机制吗? 怎么开启?](#14. MyBatis 默认会开启缓存机制吗? 怎么开启?)
  • [15. MyBatis 为什么默认不会开启二级缓存?](#15. MyBatis 为什么默认不会开启二级缓存?)
  • [16. MyBatis 中的缓存什么时候会被清理?](#16. MyBatis 中的缓存什么时候会被清理?)
  • [17. MyBatis 二级缓存清理策略有哪些?](#17. MyBatis 二级缓存清理策略有哪些?)
  • [18. MyBatis 接口绑定有哪几种方式?](#18. MyBatis 接口绑定有哪几种方式?)
  • [19. MyBatis 有哪几种 SQL 编写形式?](#19. MyBatis 有哪几种 SQL 编写形式?)
  • [20. MyBatis 映射文件中有哪些顶级元素?](#20. MyBatis 映射文件中有哪些顶级元素?)
  • [21. MyBatis 映射时 A 引用了 B,如果 B 在 A 后面会怎样?](#21. MyBatis 映射时 A 引用了 B,如果 B 在 A 后面会怎样?)
  • [22. MyBatis 中 Mapper 接口的实现原理是?](#22. MyBatis 中 Mapper 接口的实现原理是?)
  • [23. MyBatis用注解绑定和用XML文件绑定有什么区别?](#23. MyBatis用注解绑定和用XML文件绑定有什么区别?)
  • [24. MyBatis通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应, Dao 的工作原理,是否可以重载?](#24. MyBatis通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应, Dao 的工作原理,是否可以重载?)
  • [25. MyBatis 中 Mapper 中的 SQL 语句可以重载吗?](#25. MyBatis 中 Mapper 中的 SQL 语句可以重载吗?)
  • [26. MyBatis动态 sql 是做什么的?都有哪些动态 sql?能简述一下动态 sql 的执行原理不?](#26. MyBatis动态 sql 是做什么的?都有哪些动态 sql?能简述一下动态 sql 的执行原理不?)
  • [27. MyBatis实体类中的属性名和表中的字段名不一样 ,怎么办?](#27. MyBatis实体类中的属性名和表中的字段名不一样 ,怎么办?)
  • [28. MyBatis 配置文件中的 SQL id 是否能重复?](#28. MyBatis 配置文件中的 SQL id 是否能重复?)
  • [29. MyBatis 支持哪些传参数的方法?](#29. MyBatis 支持哪些传参数的方法?)
  • [30. MyBatis 的$和# 传参的区别?](# 传参的区别?)
  • [31. MyBatis 可以映射到枚举类吗?](#31. MyBatis 可以映射到枚举类吗?)
  • [32. MyBatis 怎么封装动态 SQL?](#32. MyBatis 怎么封装动态 SQL?)
  • [33. MyBatis trim 标签有什么用?](#33. MyBatis trim 标签有什么用?)
  • [34. MyBatis where 标签有什么用?](#34. MyBatis where 标签有什么用?)
  • [35. MyBatis 是如何进行分页的?分页插件的原理是什么?](#35. MyBatis 是如何进行分页的?分页插件的原理是什么?)
  • [36. MyBatis 有几种分页方式?](#36. MyBatis 有几种分页方式?)
  • [37. MyBatis 逻辑分页和物理分页的区别是什么?](#37. MyBatis 逻辑分页和物理分页的区别是什么?)
  • [38. MyBatis 流式查询有什么用?](#38. MyBatis 流式查询有什么用?)
  • [39. MyBatis 模糊查询 like 语该怎么写?](#39. MyBatis 模糊查询 like 语该怎么写?)
  • [40. MyBatis 如何防止 SQL 注入?](#40. MyBatis 如何防止 SQL 注入?)
  • [41. MyBatis 如何获取自动生成的主键id?](#41. MyBatis 如何获取自动生成的主键id?)
  • [42. MyBatis 中`jdbcType` 和`javaType` 的区别?](#42. MyBatis 中jdbcTypejavaType 的区别?)
  • [43. 什么时候必须指定`jdbcType` 和`javaType`?](#43. 什么时候必须指定jdbcTypejavaType?)
  • [44. MyBatis 支持预编译吗? 怎么做?](#44. MyBatis 支持预编译吗? 怎么做?)
  • [45. MyBatis 中的事务管理方式?](#45. MyBatis 中的事务管理方式?)
  • [46. 怎么开启事务?](#46. 怎么开启事务?)
  • [47. MyBatis 事务和 Spring 事务有什么区别?](#47. MyBatis 事务和 Spring 事务有什么区别?)
  • [48. MyBatis 使用了哪些设计模式?](#48. MyBatis 使用了哪些设计模式?)
  • [49. 什么是 JPA?](#49. 什么是 JPA?)
  • [50. MyBatis 中 `StatementHandler` 和 `MappedStatement` 区别?](#50. MyBatis 中 StatementHandlerMappedStatement 区别?)
  • [51. MyBatis 常用的 `TypeHandler` 有哪些?](#51. MyBatis 常用的 TypeHandler 有哪些?)
  • [52. MyBatis 执行流程是怎样的?](#52. MyBatis 执行流程是怎样的?)
  • [53. MyBatis 中的 `SglSession` 是线程安全的吗?](#53. MyBatis 中的 SglSession 是线程安全的吗?)
  • [54. MyBatis 中的 `SglSession` 有哪些实现类?](#54. MyBatis 中的 SglSession 有哪些实现类?)
  • [55. MyBatis 中的 `DefaultSqlSession` 为什么不是线程安全的?](#55. MyBatis 中的 DefaultSqlSession 为什么不是线程安全的?)
  • [56. MyBatis 中 `SqlSessionTemplate` 与 `SqlSessionManager` 的区别?](#56. MyBatis 中 SqlSessionTemplateSqlSessionManager 的区别?)

1. 介绍下MyBatis?

MyBatis 是一个帮你简化数据库操作的工具,特别适合 Java 程序员。它的主要作用就是让你不用自己写一堆重复的数据库操作代码。简单来说,你只需要专注写 SQL 语句,MyBatis 会帮你把这些 SQL 和 Java 对象自动关联起来。

MyBatis 的亮点:

  1. 用原生 SQL:你可以直接写熟悉的 SQL 语句,不需要学新的语法,MyBatis 帮你处理把查询结果映射到 Java 对象的麻烦。
  2. 灵活好用:对于复杂查询,MyBatis 非常灵活,不像一些全自动的框架那样限制多。
  3. 配置简单:通过简单的 XML 文件或注解,你就能快速搞定 SQL 和 Java 之间的映射关系。
  4. 动态 SQL:你可以根据不同条件动态生成 SQL,处理一些有条件的查询特别方便。
  5. 和 Spring 兼容:MyBatis 可以很好地和 Spring 一起用,整合事务管理、依赖注入这些功能。

总之,MyBatis 适合那些想要灵活控制数据库查询,又不想写太多重复代码的人。

2. MyBatis 框架的应用场景?

  1. 复杂 SQL 查询:需要灵活编写复杂 SQL,避免 ORM 生成低效查询。
  2. 现有数据库集成:对已有数据库结构进行操作,不适合全面使用 ORM 的场景。
  3. 高性能需求:需要手动优化 SQL 查询性能时。
  4. 灵活控制:需要精确控制 SQL 语句和数据库操作的应用。

它特别适合那些对 SQL 有较高控制要求的项目。

3. MyBatis 有哪些优点?

  1. 原生 SQL 灵活:可以手写 SQL,处理复杂查询。
  2. 轻量易用:配置简单,学习成本低。
  3. 动态 SQL 支持:根据条件动态生成 SQL。
  4. 高性能:手动优化 SQL,性能可控。
  5. 现有数据库友好:适合已有复杂数据库的项目。

4. MyBatis 有哪些缺点?

  1. SQL 手动编写:需要开发者手写 SQL,增加工作量。
  2. 维护成本高:复杂项目中,管理大量 SQL 语句和映射关系可能变得困难。
  3. 缺少自动化:不像 ORM 框架,无法自动生成 SQL,手动处理对象与数据库的映射。
  4. SQL 与代码耦合:SQL 与 Java 代码耦合紧密,不利于数据库迁移或改动。

这些缺点使 MyBatis 在一些复杂或大规模项目中可能增加开发和维护难度。

5. MyBatis 用到了哪些设计模式?

MyBatis 采用了多种设计模式,帮助其实现灵活性和可扩展性,主要包括以下几种:

  1. 代理模式:MyBatis 使用代理模式(动态代理)来为 Mapper 接口生成实现类,处理 SQL 语句的执行,避免手动编写实现代码。

  2. 工厂模式 :MyBatis 使用工厂模式创建 SQLSession 对象,通过 SqlSessionFactory 来管理和提供 SQLSession。

  3. 单例模式SqlSessionFactory 使用单例模式确保工厂实例在应用中只有一个,方便统一管理数据库会话。

  4. 模板方法模式 :MyBatis 中的 Executor 类使用模板方法模式,提供执行 SQL 操作的通用流程,子类可以自定义具体实现。

  5. 建造者模式:在配置解析中,MyBatis 使用建造者模式生成复杂的对象,比如解析 XML 或注解并构建相应的映射配置。

6. MyBatis常用注解有哪些?

MyBatis 常用注解有:

  1. @Select:执行查询操作。
  2. @Insert:执行插入操作。
  3. @Update:执行更新操作。
  4. @Delete:执行删除操作。
  5. @Results:自定义结果集的映射。
  6. @Result:定义单个字段的映射关系。
  7. @Param:为 SQL 语句传递参数。

这些注解用于简化 SQL 操作,替代 XML 配置。

7. MyBatis 有哪些核心组件?

  1. SqlSessionFactory :创建和管理 SqlSession 对象的工厂。
  2. SqlSession:执行 SQL 语句的接口,管理数据库会话。
  3. Executor:负责执行 SQL 语句,管理缓存和事务。
  4. Mapper 接口:映射 SQL 语句与 Java 对象的方法接口。
  5. Configuration:全局配置类,包含 MyBatis 的所有配置信息。

8. MyBatis编程步骤是什么样的?

MyBatis 的编程步骤如下:

  1. 引入 MyBatis 依赖:在项目中配置 MyBatis 所需的依赖(如 Maven 中添加依赖项)。

  2. 配置 MyBatis 环境 :编写 mybatis-config.xml,配置数据库连接信息、别名、映射文件等。

  3. 编写 Mapper 文件

    • 使用 XML 文件编写 SQL 映射(或用注解方式)。
    • 定义接口(Mapper),与 SQL 映射文件中的 SQL 语句进行绑定。
  4. 创建 SqlSessionFactory :通过 SqlSessionFactoryBuilder 读取配置文件,生成 SqlSessionFactory

  5. 使用 SqlSession 操作数据库

    • 通过 SqlSessionFactory 获取 SqlSession
    • 调用 Mapper 接口执行增删改查操作。
    • 最后关闭 SqlSession 以释放资源。
  6. 处理结果:接收数据库操作返回的结果并处理。

9. MyBatis 和JDBC有什么区别?

MyBatis 和 JDBC 的区别主要有:

  1. 代码简化:MyBatis 简化了 JDBC 中繁琐的数据库操作代码,如连接管理、结果集处理,而 JDBC 需要手动编写大量代码。
  2. SQL 映射:MyBatis 自动将 SQL 结果映射到 Java 对象,JDBC 需要手动解析结果集。
  3. 动态 SQL 支持:MyBatis 支持动态生成 SQL,而 JDBC 中 SQL 是固定的,需要手动拼接。
  4. 事务管理:MyBatis 集成了事务管理,JDBC 需要手动处理事务。

总之,MyBatis 提供了更多的自动化和简化,而 JDBC 需要更多手动控制。

10. MyBatis 中的缓存机制有啥用?

MyBatis 中的缓存机制用于提高查询性能,减少对数据库的重复访问。它包括:

  1. 一级缓存:SqlSession 级别的缓存,默认开启,同一个 SqlSession 中的相同查询结果会缓存,减少重复查询。
  2. 二级缓存:Mapper 级别的缓存,可以跨 SqlSession,缓存同一个 Mapper 下的查询结果,需手动配置。

缓存机制减少数据库压力,提升应用性能。

11. MyBatis 一级缓存和二级缓存的区别?

MyBatis 一级缓存和二级缓存的区别:

  1. 缓存范围

    • 一级缓存:SqlSession 级别,默认开启,作用范围仅在同一个 SqlSession 内。
    • 二级缓存:Mapper 级别,可以跨 SqlSession,需手动配置。
  2. 生效时机

    • 一级缓存:每次使用同一个 SqlSession 执行相同查询时生效。
    • 二级缓存:不同 SqlSession 执行相同查询时也可生效。
  3. 失效条件

    • 一级缓存:SqlSession 关闭、提交或执行更新操作后失效。
    • 二级缓存:数据更新后失效,但配置持久化时缓存内容可保存。

12. MyBatis 一级缓存和二级缓存是什么数据结构?

MyBatis 一级缓存和二级缓存都使用 HashMap 作为数据结构来存储缓存数据。

13. MyBatis 中的缓存有哪些实现类型?

MyBatis 中的缓存实现类型主要有两种:

  1. PerpetualCache(永久缓存):默认的缓存实现,基于 HashMap 存储数据。
  2. Decorator 缓存 :通过装饰器模式增强缓存功能,包括:
    • LruCache:最近最少使用缓存淘汰策略。
    • FifoCache:先进先出缓存淘汰策略。
    • SoftCache:使用软引用,内存不足时自动回收。
    • WeakCache:使用弱引用,GC 后自动回收。
    • ScheduledCache:定时清理缓存。
    • SynchronizedCache:线程安全的缓存。
    • SerializedCache:序列化存储缓存内容。

这些类型提供了不同的缓存管理策略,适应不同的需求。

14. MyBatis 默认会开启缓存机制吗? 怎么开启?

MyBatis 默认开启一级缓存,一级缓存是 SqlSession 级别的,无需额外配置。

二级缓存默认关闭,需要手动开启。开启方法如下:

  1. mybatis-config.xml 中开启全局二级缓存:

    xml 复制代码
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
  2. 在对应的 Mapper 文件或 Mapper 接口中,通过 @CacheNamespace 注解或 XML 配置开启二级缓存:

    xml 复制代码
    <cache/>

这样 MyBatis 的二级缓存就会被启用。

15. MyBatis 为什么默认不会开启二级缓存?

MyBatis 默认不启用二级缓存,主要是出于以下考虑:

  1. 数据一致性问题:二级缓存是跨 SqlSession 的,数据更新后如果没有及时刷新缓存,可能导致脏数据(缓存与数据库不一致)。

  2. 内存占用:二级缓存存储在内存中,可能会占用较多内存资源,影响系统性能。

  3. 适用场景有限:二级缓存适合查询频繁、更新较少的场景,但并不适合所有项目,默认关闭可以避免不必要的性能开销。

因此,MyBatis 让开发者根据实际需求手动开启二级缓存。

16. MyBatis 中的缓存什么时候会被清理?

MyBatis 中缓存的清理时机如下:

  1. 一级缓存(SqlSession 级别缓存):

    • SqlSession 关闭时,一级缓存会被清理。
    • 当在同一个 SqlSession 中执行 INSERTUPDATEDELETE 操作时,一级缓存会自动清空,确保数据一致性。
    • 当手动调用 clearCache() 方法时,也会清理一级缓存。
  2. 二级缓存(Mapper 级别缓存):

    • 当执行 INSERTUPDATEDELETE 操作时,二级缓存会被清除,确保数据一致性。
    • 二级缓存也可以通过自定义的缓存策略(如时间策略或大小限制)自动清理。
    • 如果使用了带有过期策略的缓存装饰器(如 ScheduledCache),缓存会根据设定的时间间隔清理。
    • 可以通过调用 clearCache() 方法手动清除二级缓存。

总结来说,缓存会在数据库发生修改操作或通过特定策略、手动清理时被清理,以保证数据的一致性和缓存的有效性。

17. MyBatis 二级缓存清理策略有哪些?

MyBatis 二级缓存的清理策略主要有:

  1. 自动清理 :执行 INSERTUPDATEDELETE 操作时,缓存会自动清空。
  2. 基于时间的清理 :使用 ScheduledCache,按照设定的时间间隔清理缓存。
  3. 基于缓存淘汰策略
    • LruCache:最近最少使用的缓存项会被清除。
    • FifoCache:按照先入先出的顺序清理缓存。
  4. 手动清理 :可以通过调用 clearCache() 方法手动清除缓存。

18. MyBatis 接口绑定有哪几种方式?

MyBatis 接口绑定有两种方式:

  1. XML 文件方式:在 Mapper 接口中定义方法,并通过对应的 XML 文件绑定 SQL 语句。
  2. 注解方式 :直接在 Mapper 接口的方法上使用注解(如@Select@Insert@Update@Delete 等)编写 SQL,实现绑定。

这两种方式都可以将 SQL 语句与接口方法关联起来。

19. MyBatis 有哪几种 SQL 编写形式?

MyBatis 支持以下两种 SQL 编写形式:

  1. XML 文件形式:在 XML 文件中编写 SQL 语句,通过 Mapper 接口方法绑定。
  2. 注解形式 :直接在 Mapper 接口的方法上使用注解(如 @Select@Insert@Update@Delete)编写 SQL。

这两种方式都可以用于实现 SQL 操作,选择哪种形式取决于项目需求。

20. MyBatis 映射文件中有哪些顶级元素?

MyBatis 映射文件中的顶级元素主要包括:

  1. <cache>:配置缓存策略。
  2. <cache-ref>:引用其他命名空间的缓存。
  3. <resultMap>:定义结果集映射规则。
  4. <sql>:定义可复用的 SQL 片段。
  5. <insert><update><delete><select>:定义 SQL 操作语句。

这些元素是 MyBatis 映射文件的核心组成部分。

21. MyBatis 映射时 A 引用了 B,如果 B 在 A 后面会怎样?

在 MyBatis 映射文件中,如果映射 A 引用了映射 B,而 B 的定义在 A 之后,通常会导致 MyBatis 报错。因为 MyBatis 解析映射文件时是顺序进行的,当解析到 A 时,它会试图找到 B,但此时 B 还未被解析,因此会抛出 Invalid Reference 等类似的错误。

为避免这种问题,可以通过以下方式解决:

  1. 调整顺序 :确保 BA 之前定义。
  2. 使用命名空间引用 :将 B 放在其他映射文件中并通过命名空间引用,确保引用的映射在加载时已经存在。

顺序错误会直接影响 MyBatis 的解析,因此需要特别注意映射文件中引用的顺序。

22. MyBatis 中 Mapper 接口的实现原理是?

MyBatis 中 Mapper 接口的实现原理是通过动态代理生成接口的实现类。MyBatis 根据 Mapper 接口的方法签名自动生成 SQL 语句,并在运行时由 SqlSession 提供执行,返回对应的查询结果。这样开发者只需定义接口和 SQL 映射,不需要手动编写实现类。

23. MyBatis用注解绑定和用XML文件绑定有什么区别?

MyBatis 中注解绑定和 XML 文件绑定的区别如下:

  1. 注解绑定

    • SQL 语句直接写在 Mapper 接口的方法上,通过注解(如 @Select, @Insert, @Update, @Delete)定义。
    • 适合简单的 SQL 语句,代码集中在一个地方,维护方便。
    • 适合轻量级项目,不需要单独的 XML 文件。
  2. XML 文件绑定

    • SQL 语句保存在独立的 XML 文件中,通过 <select>, <insert>, <update>, <delete> 等标签定义。
    • 适合复杂 SQL,尤其是动态 SQL,XML 提供更灵活的控制。
    • 便于与业务逻辑分离,SQL 语句与代码解耦,易于维护和扩展。

简而言之,注解适合简单 SQL,XML 更适合复杂 SQL 和动态 SQL。

24. MyBatis通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应, Dao 的工作原理,是否可以重载?

在 MyBatis 中,每个 XML 映射文件通常对应一个 DAO(Data Access Object)接口。DAO 接口的工作原理 是通过 MyBatis 的动态代理机制:MyBatis 自动生成 DAO 接口的实现类,通过 SqlSession 执行映射文件中的 SQL 语句,并将结果返回给调用者。

DAO 接口中的方法可以重载,即在同一个接口中,可以定义多个方法名相同但参数类型或数量不同的方法。然而,需要注意的是:

  • MyBatis 会根据方法签名(包括方法名和参数类型)确定调用哪个 SQL 语句。
  • 在 XML 映射文件中,每个重载的方法需要对应唯一的 <select>, <insert>, <update>, <delete> 标签,这些标签需要通过 id 唯一标识,每个 id 应与重载方法匹配。

因此,DAO 接口方法可以重载,但需要确保 XML 映射文件中的 id 能唯一标识每个方法。

25. MyBatis 中 Mapper 中的 SQL 语句可以重载吗?

MyBatis 中 SQL 语句不能直接重载 ,因为 SQL 是通过 Mapper 方法的名字和参数唯一映射的。如果方法重载,MyBatis 无法区分不同方法的 SQL。

解决方式:

  1. 使用不同的方法名。
  2. 使用动态 SQL 实现条件判断。
  3. 使用 @Param 区分参数。

重载本质上需要避免方法和 SQL 映射冲突。

26. MyBatis动态 sql 是做什么的?都有哪些动态 sql?能简述一下动态 sql 的执行原理不?

MyBatis 动态 SQL 用于根据条件动态生成 SQL 语句,避免写多个 SQL。

常用动态 SQL:

  1. <if>:条件判断。
  2. <choose> :类似 switch-case
  3. <trim>:去除多余的前后缀。
  4. <where> :自动添加 WHERE
  5. <set> :处理 UPDATE 语句。
  6. <foreach> :循环生成 SQL,常用于 IN 子句。

执行原理:根据传入参数,动态解析 SQL 标签生成最终 SQL,并执行。

27. MyBatis实体类中的属性名和表中的字段名不一样 ,怎么办?

在 MyBatis 中,如果实体类的属性名与数据库表中的字段名不一致,可以通过以下两种方式进行映射:

  1. 使用 @Results 注解

    在 Mapper 接口的方法上通过 @Results 注解手动指定实体类属性与数据库字段的对应关系。

    java 复制代码
    @Select("SELECT id, user_name FROM users")
    @Results({
        @Result(property = "userName", column = "user_name")
    })
    List<User> selectUsers();
  2. 在 XML 映射文件中使用 <resultMap>

    通过 XML 配置文件的 <resultMap> 元素将表字段与实体类属性进行映射。

    xml 复制代码
    <resultMap id="userMap" type="User">
        <result property="userName" column="user_name"/>
    </resultMap>
    
    <select id="selectUsers" resultMap="userMap">
        SELECT id, user_name FROM users
    </select>

这两种方式都可以解决实体类属性名和表字段名不一致的问题。

28. MyBatis 配置文件中的 SQL id 是否能重复?

在 MyBatis 配置文件中,SQL id 不能重复id 是每个 SQL 语句的唯一标识,用于在 Mapper 接口中引用特定的 SQL 语句。如果同一个 id 重复,MyBatis 会抛出异常,导致系统无法正常工作。

因此,确保每个 id 在同一 Mapper 文件中都是唯一的,以避免冲突。

29. MyBatis 支持哪些传参数的方法?

MyBatis 支持以下几种传参方法:

  1. 单个参数 :传递简单类型或对象,SQL 中用 #{param} 访问。

  2. 多个参数 :使用 @Param 注解,例如:

    java 复制代码
    List<User> findUser(@Param("id") int id, @Param("name") String name);
  3. 传递对象 :传递实体对象,SQL 中用 #{user.id} 访问属性。

  4. 使用 Map 传参 :通过 Map 传递参数,SQL 中用 #{key} 访问值。

这些方法提供了灵活的参数传递方式。

30. MyBatis 的$和# 传参的区别?

在 MyBatis 中,$# 传参的区别如下:

  1. #(安全的参数占位符)

    • 使用 # 时,MyBatis 会对传入的参数进行预处理,防止 SQL 注入。
    • 适用于 SQL 语句中的参数替换,例如:SELECT * FROM users WHERE id = #{id}
  2. $(直接字符串替换)

    • 使用 $ 时,MyBatis 直接将参数作为字符串替换,不进行任何处理
    • 适用于动态表名、列名等场景,例如:SELECT * FROM ${tableName}
    • 由于不安全,容易引发 SQL 注入,需谨慎使用。

31. MyBatis 可以映射到枚举类吗?

  1. 默认映射

    • 如果枚举名称与数据库字段值相同,MyBatis 会自动映射。
    java 复制代码
    public enum Status {
        ACTIVE, INACTIVE;
    }
  2. 自定义类型处理器

    • 如果需要自定义映射,可以实现 BaseTypeHandler
    java 复制代码
    public class StatusTypeHandler extends BaseTypeHandler<Status> {
        @Override
        public void setNonNullParameter(PreparedStatement ps, int i, Status parameter, JdbcType jdbcType) throws SQLException {
            ps.setString(i, parameter.name());
        }
        @Override
        public Status getNullableResult(ResultSet rs, String columnName) throws SQLException {
            return Status.valueOf(rs.getString(columnName));
        }
    }
  3. 在 XML 中指定类型处理器

    • 在 SQL 映射中指定使用自定义类型处理器。
    xml 复制代码
    <resultMap id="userMap" type="User">
        <result property="status" column="status_column" typeHandler="com.example.StatusTypeHandler"/>
    </resultMap>

总结:MyBatis 支持直接映射枚举或使用自定义类型处理器进行映射。

32. MyBatis 怎么封装动态 SQL?

在 MyBatis 中,封装动态 SQL 可以通过以下几种方式实现:

  1. XML 映射文件
    使用动态 SQL 标签,如 <if><choose>
xml 复制代码
<select id="findUsers" resultType="User">
    SELECT * FROM users
    WHERE 1=1
    <if test="name != null">
        AND name = #{name}
    </if>
    <if test="status != null">
        AND status = #{status}
    </if>
</select>
  1. 注解方式
    在 Mapper 接口中使用注解和脚本:
java 复制代码
@Select({
    "<script>",
    "SELECT * FROM users",
    "WHERE 1=1",
    "<if test='name != null'>",
    "AND name = #{name}",
    "</if>",
    "<if test='status != null'>",
    "AND status = #{status}",
    "</if>",
    "</script>"
})
List<User> findUsers(@Param("name") String name, @Param("status") String status);
  1. 查询条件对象
    定义一个查询条件对象,封装参数:
java 复制代码
public class UserQuery {
    private String name;
    private String status;
    // getters and setters
}

在 XML 中使用:

xml 复制代码
<select id="findUsers" resultType="User">
    SELECT * FROM users
    WHERE 1=1
    <if test="name != null">
        AND name = #{name}
    </if>
    <if test="status != null">
        AND status = #{status}
    </if>
</select>

33. MyBatis trim 标签有什么用?

MyBatis 中的 <trim> 标签用于处理 SQL 语句的前后缀,简化 SQL 的构建过程。它的主要作用是去除多余的分隔符(如 ANDOR),确保生成的 SQL 语句语法正确。

主要功能:

  1. 去除前缀

    • 可以在 SQL 语句开始前去除特定的前缀(如 ANDOR)。
  2. 去除后缀

    • 可以在 SQL 语句结束后去除特定的后缀(如 ANDOR)。
  3. 处理空值

    • 只有在满足某个条件时,才会添加对应的 SQL 部分。

示例:

xml 复制代码
<select id="findUsers" resultType="User">
    SELECT * FROM users
    <where>
        <trim prefix="WHERE" prefixOverrides="AND |OR ">
            <if test="name != null">
                AND name = #{name}
            </if>
            <if test="status != null">
                AND status = #{status}
            </if>
        </trim>
    </trim>
</select>

总结:<trim> 标签可以有效管理 SQL 语句中的多余分隔符,使动态 SQL 的构建更加灵活和简洁。

34. MyBatis where 标签有什么用?

MyBatis 中的 <where> 标签用于自动处理 SQL 语句中的 WHERE 子句,主要功能包括:

  1. 自动添加 WHERE :在有条件时自动插入 WHERE 关键字。
  2. 去除多余的 ANDOR :如果条件成立,自动去除多余的 ANDOR,确保 SQL 语法正确。

示例:

xml 复制代码
<select id="findUsers" resultType="User">
    SELECT * FROM users
    <where>
        <if test="name != null">
            AND name = #{name}
        </if>
        <if test="status != null">
            AND status = #{status}
        </if>
    </where>
</select>

35. MyBatis 是如何进行分页的?分页插件的原理是什么?

MyBatis 进行分页的常用方式是通过 分页插件 ,如 PageHelper。以下是其基本步骤和原理:

  1. 使用步骤
  • 添加依赖:在项目中添加分页插件的依赖。

  • 配置插件:在 MyBatis 配置文件中注册分页插件。

    xml 复制代码
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/> <!-- 数据库类型 -->
        </plugin>
    </plugins>
  • 调用分页方法:在查询前设置分页参数。

    java 复制代码
    PageHelper.startPage(pageNum, pageSize); // 设置当前页和每页大小
    List<User> users = userMapper.findAll(); // 查询数据
  1. 原理
  • 拦截器:分页插件通过 MyBatis 的插件机制拦截 SQL 执行。
  • SQL 修改 :插件修改原始 SQL,添加 LIMITOFFSET 以实现分页。
  • 结果封装:将结果封装成分页对象,包含总记录数和分页数据。

36. MyBatis 有几种分页方式?

MyBatis 有以下几种分页方式:

  1. 使用分页插件 :如 PageHelper,通过拦截器自动处理 SQL 进行分页。

  2. 手动分页 :在 SQL 中手动添加 LIMITOFFSET,根据传入的参数控制分页。

  3. 使用 RowBounds :使用 RowBounds 对象进行内存中的分页,不改变原始 SQL。

37. MyBatis 逻辑分页和物理分页的区别是什么?

  1. 逻辑分页
  • 定义:逻辑分页是指在应用层面进行分页处理,查询所有数据后再在内存中进行分页。
  • 特点
    • 所有数据一次性加载到内存中,适合数据量小的场景。
    • 可能会导致性能问题,因为需要处理完整的数据集。
  • 实现方式 :通过 RowBounds 或手动切分结果集。
  1. 物理分页
  • 定义:物理分页是指在数据库层面通过 SQL 语句进行分页,仅查询需要的数据。
  • 特点
    • 只查询当前页的数据,节省了内存和网络传输资源。
    • 更适合大数据量的场景,性能更优。
  • 实现方式 :通过 LIMITOFFSET 或使用分页插件(如 PageHelper)。
  1. 总结
  • 逻辑分页:在应用层处理,适合小数据集,可能影响性能。
  • 物理分页:在数据库层处理,适合大数据集,性能更佳。

38. MyBatis 流式查询有什么用?

  1. 减少内存占用

    逐行处理查询结果,避免一次性加载所有数据到内存中。

  2. 提高性能

    允许在结果加载时进行后续操作,缩短响应时间。

  3. 适用于大数据集

    有效解决无法一次性加载大数据集的问题。

  4. 示例

    使用 ResultHandler 逐行处理结果:

java 复制代码
sqlSession.select("namespace.selectStatement", new ResultHandler<User>() {
    @Override
    public void handleResult(ResultContext<? extends User> resultContext) {
        User user = resultContext.getResultObject();
        // 逐行处理 user 对象
    }
});

39. MyBatis 模糊查询 like 语该怎么写?

在 MyBatis 中,进行模糊查询可以使用 LIKE 关键字,通常结合 SQL 的通配符 % 来实现。

  1. XML 映射文件中的模糊查询
xml 复制代码
<select id="findUsersByName" resultType="User">
    SELECT * FROM users
    WHERE name LIKE CONCAT('%', #{name}, '%')
</select>
  1. 使用注解的方式
java 复制代码
@Select("SELECT * FROM users WHERE name LIKE CONCAT('%', #{name}, '%')")
List<User> findUsersByName(@Param("name") String name);
  1. 传递参数
    在调用时,将需要模糊匹配的字符串传入查询方法中:
java 复制代码
List<User> users = userMapper.findUsersByName("张三");

总结:使用 LIKE 结合 % 通配符,可以在 MyBatis 中实现模糊查询。通过 XML 或注解都可以轻松实现。

40. MyBatis 如何防止 SQL 注入?

MyBatis 防止 SQL 注入主要通过以下方式:

  1. 使用预编译语句 :通过参数化查询(#{})来绑定参数,避免直接拼接 SQL 字符串。

    xml 复制代码
    <select id="findUser" resultType="User">
        SELECT * FROM users WHERE username = #{username}
    </select>
  2. 避免直接拼接 SQL:不使用字符串拼接构建 SQL 语句,确保输入参数经过处理。

  3. 使用 MyBatis 的内置功能 :使用内置的 @Param 注解来安全地传递参数。

  4. 输入验证:在应用层进行输入验证,确保参数合法。

总结:通过参数化查询、避免拼接 SQL 和输入验证,MyBatis 有效防止 SQL 注入。

41. MyBatis 如何获取自动生成的主键id?

在 MyBatis 中获取自动生成的主键 ID 的方法如下:

  1. 使用 XML 映射
xml 复制代码
<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO users (username, password) VALUES (#{username}, #{password})
</insert>
  1. 使用注解
java 复制代码
@Insert("INSERT INTO users (username, password) VALUES (#{username}, #{password})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertUser(User user);
  1. 获取 ID

插入后,自动生成的主键会赋值给对象的 id 属性:

java 复制代码
User user = new User();
user.setUsername("张三");
user.setPassword("password");
userMapper.insertUser(user);
Long generatedId = user.getId(); // 获取主键 ID

42. MyBatis 中jdbcTypejavaType 的区别?

  1. jdbcType
  • 定义:表示数据库中列的数据类型。
  • 用途:用于确定如何处理数据库中的数据,影响 SQL 语句的生成和执行。
  • 示例 :如 VARCHARINTEGERDATE 等。
  1. javaType
  • 定义:表示 Java 中对应的数据类型。
  • 用途:用于将数据库中的数据映射到 Java 对象的属性。
  • 示例 :如 StringIntegerDate 等。

总的来说,javaTypejdbcType都是用来处理数据类型的,javaType主要用来处理Java对象到数据库的映射,而jdbcType主要用来处理数据库类型和JDBC之间的关系。

43. 什么时候必须指定jdbcTypejavaType?

在 MyBatis 中,必须指定 jdbcTypejavaType 的情况主要有以下几种:

  1. jdbcType
  • NULL 值处理 :当字段可以为 NULL 时,必须显式指定 jdbcType,以便正确处理空值。
  • 特定类型映射 :对于一些特殊或不常用的数据类型,如 BLOBCLOB 等,建议指定 jdbcType 以确保正确处理。
  1. javaType
  • 复杂类型 :当字段类型是复杂类型(如自定义对象或集合)时,必须指定 javaType,以确保正确映射到 Java 类型。
  • 不匹配类型 :当数据库字段类型与 Java 类型不一致时,需要明确指定 javaType 以避免类型转换错误。

示例

xml 复制代码
<resultMap id="UserMap" type="User">
    <result property="id" column="id" jdbcType="INTEGER" javaType="java.lang.Integer"/>
    <result property="username" column="username" jdbcType="VARCHAR" javaType="java.lang.String"/>
    <result property="createdDate" column="created_date" jdbcType="TIMESTAMP" javaType="java.util.Date"/>
</resultMap>

总结:必须在处理 NULL 值、复杂类型或类型不匹配时显式指定 jdbcTypejavaType

44. MyBatis 支持预编译吗? 怎么做?

MyBatis 支持预编译,主要通过参数化查询来实现。具体做法如下:

  1. 使用参数化查询
    使用 #{} 语法指定参数,MyBatis 会自动进行预编译。

示例

XML 映射文件

xml 复制代码
<select id="findUserById" resultType="User">
    SELECT * FROM users WHERE id = #{id}
</select>

Mapper 接口

java 复制代码
User findUserById(@Param("id") int id);

总结:MyBatis 通过参数化查询(#{})实现预编译,确保 SQL 安全性和性能优化。

45. MyBatis 中的事务管理方式?

  1. 编程式事务管理
  • 通过 SqlSession 控制事务
    • 手动控制事务的开始、提交和回滚。
    • 适合需要细粒度控制的场景。
java 复制代码
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
    // 开始事务
    // 执行操作
    sqlSession.commit(); // 提交事务
} catch (Exception e) {
    sqlSession.rollback(); // 回滚事务
} finally {
    sqlSession.close();
}
  1. 声明式事务管理
  • 结合 Spring 框架使用
    • 通过 @Transactional 注解自动管理事务。
    • 适合简单配置和一致性需求的场景。
java 复制代码
@Service
public class UserService {
    @Transactional
    public void addUser(User user) {
        // 执行数据库操作
    }
}

总结:MyBatis 提供编程式和声明式两种事务管理方式,编程式适合细粒度控制,声明式适合与 Spring 结合使用。

46. 怎么开启事务?

  1. 编程式事务管理
java 复制代码
SqlSession sqlSession = sqlSessionFactory.openSession(); // 开启事务
try {
    // 执行数据库操作
    sqlSession.commit(); // 提交事务
} catch (Exception e) {
    sqlSession.rollback(); // 回滚事务
} finally {
    sqlSession.close(); // 关闭会话
}
  1. 声明式事务管理(与 Spring 结合使用)
java 复制代码
@Service
public class UserService {
    @Transactional // 开启事务
    public void addUser(User user) {
        // 执行数据库操作
    }
}

总结

  • 编程式 :使用 SqlSession 手动管理事务。
  • 声明式 :使用 @Transactional 注解自动处理事务。

47. MyBatis 事务和 Spring 事务有什么区别?

  1. 事务管理方式
  • MyBatis 事务

    • 主要通过 SqlSession 手动管理,支持编程式事务控制。
    • 事务的开始、提交和回滚需要显式调用。
  • Spring 事务

    • 提供了声明式事务管理,可以通过 @Transactional 注解自动处理事务。
    • 可以与多种数据访问技术(如 JPA、Hibernate)结合使用。
  1. 事务范围
  • MyBatis 事务

    • 主要针对 MyBatis 的操作,事务的控制相对简单。
  • Spring 事务

    • 可以跨多个持久化层和服务层操作,支持更复杂的事务管理。
  1. 事务传播行为
  • MyBatis 事务

    • 没有内置的事务传播机制,需要手动实现。
  • Spring 事务

    • 提供多种事务传播行为(如 REQUIREDREQUIRES_NEW),可以灵活管理事务的传播和隔离级别。
  1. 集成支持
  • MyBatis 事务

    • 主要与 MyBatis 自身的会话管理结合。
  • Spring 事务

    • 支持多种持久化框架和不同的事务管理器,易于集成。

总结:

  • MyBatis 事务:手动控制,适合简单场景。
  • Spring 事务:声明式管理,支持复杂事务和多种持久化框架。

48. MyBatis 使用了哪些设计模式?

MyBatis 使用了以下设计模式:

  1. 代理模式:通过动态代理实现接口的实现,简化数据库操作。

  2. 工厂模式 :使用 SqlSessionFactory 创建 SqlSession,解耦对象创建过程。

  3. 单例模式SqlSessionFactory 通常采用单例模式,以确保只创建一个实例,优化资源使用。

  4. 模板方法模式:定义了操作的框架,允许子类(具体实现)重写某些步骤,但不改变算法的结构。

  5. 建造者模式:在创建复杂 SQL 语句时,通过构建器模式分步构造 SQL 语句。

总结:MyBatis 利用代理、工厂、单例、模板方法和建造者等设计模式,实现了灵活、可扩展和易于维护的数据库访问框架。

49. 什么是 JPA?

JPA(Java Persistence API)是 Java 平台的标准规范,用于管理 Java 对象与数据库之间的持久化。它主要特点包括:

  1. 对象关系映射(ORM):将 Java 对象映射到数据库表。
  2. 持久化上下文:管理实体生命周期,确保数据一致性。
  3. 查询语言:提供 JPQL(Java Persistence Query Language)用于查询实体。
  4. 事务管理:支持与 JTA 集成,管理事务。
  5. 厂商独立性:支持多种实现(如 Hibernate、EclipseLink)。

总结:JPA 简化了 Java 应用程序的数据库操作,提供标准化的持久化解决方案。

50. MyBatis 中 StatementHandlerMappedStatement 区别?

在 MyBatis 中,StatementHandlerMappedStatement 的区别如下:

  1. MappedStatement
  • 定义:表示 SQL 映射语句的元数据,包括 SQL 语句、参数类型、返回类型等信息。
  • 作用:用于配置和描述特定的 SQL 语句及其相关信息,通常在 XML 映射文件或注解中定义。
  1. StatementHandler
  • 定义 :用于执行 SQL 语句的接口,负责创建和管理 PreparedStatement
  • 作用:处理 SQL 执行的具体逻辑,包括参数设置、执行查询和处理结果集。

总结:

  • MappedStatement:用于描述 SQL 映射及其元数据。
  • StatementHandler:负责执行 SQL 语句的具体实现。

51. MyBatis 常用的 TypeHandler 有哪些?

MyBatis 常用的 TypeHandler 包括以下几种:

  1. BasicTypeHandler

    • 默认的类型处理器,处理基本类型(如 intString 等)与数据库类型之间的映射。
  2. EnumTypeHandler

    • 用于处理 Java 枚举类型与数据库值之间的映射。
  3. DateTypeHandler

    • 用于处理 java.util.Datejava.sql.Datejava.sql.Timestamp 等日期类型。
  4. JsonTypeHandler

    • 用于处理 JSON 字符串与 Java 对象之间的映射,通常与 JSON 库(如 Jackson 或 Gson)结合使用。
  5. BlobTypeHandler

    • 用于处理 BLOB(二进制大对象)数据类型的映射,适合存储二进制数据。
  6. ClobTypeHandler

    • 用于处理 CLOB(字符大对象)数据类型的映射,适合存储大文本数据。

52. MyBatis 执行流程是怎样的?

MyBatis 的执行流程如下:

  1. 创建 SqlSessionFactory

    • 从 MyBatis 配置文件中读取配置信息,创建 SqlSessionFactory 实例。
  2. 打开 SqlSession

    • 通过 SqlSessionFactory 打开一个 SqlSession,开始数据库操作。
  3. 映射语句的调用

    • 调用 Mapper 接口中的方法,传入参数,MyBatis 根据方法名查找对应的 MappedStatement
  4. 执行 SQL 语句

    • StatementHandler 根据 MappedStatement 创建 SQL 语句,并执行数据库操作(如查询、插入、更新等)。
  5. 处理结果

    • 将数据库返回的结果集映射为 Java 对象(实体),并返回给调用者。
  6. 提交或回滚事务

    • 如果是手动管理事务,根据操作结果选择提交或回滚事务。
  7. 关闭 SqlSession

    • 关闭 SqlSession,释放资源。

总结:MyBatis 的执行流程从创建 SqlSessionFactory 到关闭 SqlSession,包括 SQL 映射、执行和结果处理等步骤。

53. MyBatis 中的 SglSession 是线程安全的吗?

MyBatis 中的 SqlSession 不是线程安全 的。每个 SqlSession 实例应当在一个线程内独立使用,不能被多个线程共享。为了确保线程安全,通常的做法是每个线程都创建自己的 SqlSession 实例,使用完成后及时关闭。

54. MyBatis 中的 SglSession 有哪些实现类?

在 MyBatis 中,SqlSession 的主要实现类包括:

  1. DefaultSqlSession

    • MyBatis 默认的 SqlSession 实现,提供了基本的数据库操作功能。
  2. SqlSessionManager

    • 用于管理多个 SqlSession 的生命周期,支持事务控制。
  3. SqlSessionTemplate(Spring 集成):

    • 提供线程安全的 SqlSession 实现,适用于 Spring 环境,支持 Spring 的事务管理。

55. MyBatis 中的 DefaultSqlSession 为什么不是线程安全的?

DefaultSqlSession 在 MyBatis 中不是线程安全的,主要原因包括:

  1. 状态管理

    • DefaultSqlSession 维护了内部状态,如连接、事务和缓存等,这些状态在多个线程中共享可能导致数据不一致。
  2. 资源共享

    • 它包含对数据库连接的引用和其他资源,多个线程同时访问可能导致并发问题。
  3. 设计目的

    • SqlSession 设计为短暂的、一次性的会话,旨在处理单一数据库操作,适合在一个线程中使用。

56. MyBatis 中 SqlSessionTemplateSqlSessionManager 的区别?

SqlSessionTemplateSqlSessionManager 在 MyBatis 中的区别如下:

  1. 用途
  • SqlSessionTemplate

    • 用于在 Spring 环境中提供线程安全的 SqlSession,支持 Spring 的事务管理。适合在 Spring Bean 中使用。
  • SqlSessionManager

    • 用于管理多个 SqlSession 的生命周期,提供事务控制和批量处理功能。适合在需要手动管理 SqlSession 的场景中使用。
  1. 线程安全
  • SqlSessionTemplate

    • 线程安全,可以被多个线程共享,适合在多线程环境中使用。
  • SqlSessionManager

    • 本身并不保证线程安全,通常在每个线程中创建独立的 SqlSession
  1. 事务管理
  • SqlSessionTemplate

    • 自动与 Spring 的事务管理集成,简化事务处理。
  • SqlSessionManager

    • 提供手动的事务控制,适合复杂的事务管理场景。

总结:

  • SqlSessionTemplate:线程安全,适合 Spring 环境,自动集成事务管理。
  • SqlSessionManager :管理多个 SqlSession,不保证线程安全,适合手动事务控制。
相关推荐
远歌已逝17 分钟前
维护在线重做日志(二)
数据库·oracle
jokerest1234 小时前
web——sqliabs靶场——第十三关——报错注入+布尔盲注
mybatis
武子康5 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
WindFutrue8 小时前
使用Mybatis向Mysql中的插入Point类型的数据全方位解析
数据库·mysql·mybatis
AiFlutter8 小时前
Java实现简单的搜索引擎
java·搜索引擎·mybatis
LKID体9 小时前
Python操作neo4j库py2neo使用(一)
python·oracle·neo4j
斗-匕9 小时前
Spring事务管理
数据库·spring·oracle
一行玩python10 小时前
SQLAlchemy,ORM的Python标杆!
开发语言·数据库·python·oracle
王ASC11 小时前
ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值。ojdbc8版本23.2.0.0驱动BUG【已解决】
数据库·sql·oracle
天天扭码12 小时前
五天SpringCloud计划——DAY1之mybatis-plus的使用
java·spring cloud·mybatis