类
MappedStatement
基本概念
MappedStatement是MyBatis框架中的一个核心类,它代表了一个映射语句(SQL语句)的配置信息。在MyBatis中,每个映射语句都对应一个MappedStatement对象。
MappedStatement类封装了映射语句的各种配置信息,并提供了相应的方法来获取和操作这些信息。它在MyBatis框架中起到了非常重要的作用,负责将映射语句的配置转化为可执行的SQL语句,并处理输入参数和输出结果的映射关系。通过MappedStatement类,MyBatis可以实现动态SQL的生成和执行,提供了灵活而强大的数据访问能力。
源码
属性
id
每个 MappedStatement 的唯一标识,通常对应 Mapper 接口中的方法名。
sqlSource
包含 SQL 语句的源信息,负责生成最终的 SQL 语句,包括动态 SQL 的处理。
parameterType
指定传入 SQL 的参数类型,通常是 Java 类的全名,便于 MyBatis 进行参数的类型转换。
resultType
指定 SQL 执行后返回的结果类型,通常也是 Java 类的全名,帮助 MyBatis 将查询结果映射为 Java 对象
resultMap
用于指定返回结果的映射关系,可以通过定义的 resultMap 来处理复杂的结果集。
cache
相关的缓存配置,定义 SQL 语句的缓存策略。
flushCacheRequired
表示在执行该语句后是否需要刷新缓存。
useCache
指示是否使用二级缓存。
timeout
SQL 执行的超时时间。
fetchSize
每次从数据库获取的记录数,用于优化性能。
statementType
SQL 语句的类型,可能是 STATEMENT, PREPARED, 或 CALLABLE。
1、STATEMENT
说明: 直接执行原始 SQL 语句。
使用场景: 当你不需要预编译 SQL 语句时,可以使用这种类型。这适用于简单的查询或操作,例如单个查询语句。
优缺点:
优点: 直接执行,无需预编译,适合快速执行。
缺点: 每次执行时都需要解析 SQL,可能导致性能下降,尤其是在重复执行相同的 SQL 时。
2. PREPARED
说明: 使用预编译的 SQL 语句。
使用场景: 当 SQL 语句中包含参数时,MyBatis 将使用这个类型。这种方式通常用于需要多次执行的 SQL 语句。
优缺点:
优点: SQL 只解析一次,适合重复执行相同的 SQL,能提高性能和安全性(防止 SQL 注入)。
缺点: 在某些情况下,第一次执行可能稍慢,因为需要进行预编译。
3. CALLABLE
说明: 用于调用存储过程。
使用场景: 当需要执行存储过程时,使用这个类型。
优缺点:
优点: 能直接调用数据库中定义的存储过程,适合复杂的业务逻辑处理。
缺点: 存储过程的复杂性可能使得维护和调试变得困难。
SQL映射信息
SQL 语句:存储实际执行的 SQL 语句,可以是静态 SQL 或动态 SQL。
参数类型:定义传入 SQL 的参数类型,确保类型安全。
返回类型:指定 SQL 执行后返回的结果类型,便于结果映射。
配置与元数据
命名空间:指示该 SQL 语句属于哪个 Mapper 接口,有助于 MyBatis 进行组织与管理。
ID:每个 MappedStatement 由一个唯一的 ID 标识,通常对应 Mapper 接口中的方法名。
缓存策略:配置与该语句相关的缓存设置,允许结果缓存以提高性能。
执行策略
执行类型:定义该语句的执行方式,如查询、插入、更新或删除。
拦截器:相关的拦截器配置,支持对执行过程的增强。
使用示例
在配置文件中,你可能会看到如下定义:
在这个例子中,selectUser 会生成一个对应的 MappedStatement 实例,包含 SQL 语句、参数类型和返回类型等信息。
BaseTypeHandler
基本概念
MyBatis 中的 BaseTypeHandler 是一个抽象类,它用于处理 Java 类型与数据库类型之间的转换。MyBatis 提供了一些内置的 TypeHandler 实现,但有时你可能需要自定义类型转换逻辑。在这种情况下可以通过继承 BaseTypeHandler 类来实现自己的 TypeHandler。
BaseTypeHandler 是 TypeHandler 接口的一个基础实现,它提供了一些默认的实现方法,可以简化你自己实现 TypeHandler 时的代码量。
源码
方法
setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType)
设置 SQL 参数的方法。
getResult(ResultSet rs, String columnName)
通过列名从 ResultSet 获取结果。
getResult(ResultSet rs, int columnIndex)
通过列索引从 ResultSet 获取结果。
getResult(CallableStatement cs, int columnIndex)
通过列索引从 CallableStatement 获取结果。
使用场景
1、自定义 Java 类型与数据库类型之间的转换:例如,某些数据库字段存储的是 JSON 字符串,而你希望将其映射为一个 Java 对象。
2、处理数据库中不常见的数据类型:例如,数据库中有些字段存储特殊的枚举类型或自定义类型,你希望自定义转换逻辑。
代码示例
配置方式
总结
BaseTypeHandler简化了自定义类型处理器的开发,只需继承它并实现核心转换方法即可。
MybatisEnumTypeHandler
基本概念
MybatisEnumTypeHandler 是 MyBatis 中用于处理枚举类型的类型处理器。它的主要作用是将 Java 枚举类型与数据库中对应的列类型之间进行转换。具体来说,当你在 Java 对象中使用枚举类型时,MybatisEnumTypeHandler 可以将其正确地存储到数据库中,以及从数据库中读取数据并转换为相应的枚举值。
主要功能
1、枚举与数据库之间的转换
将枚举值转换为数据库支持的类型(通常是字符串或整数),以便存储在数据库中。
将从数据库中读取的数据转换为相应的枚举类型。
2、支持多种枚举类型
MybatisEnumTypeHandler 可以处理任意的 Java 枚举类型,而不局限于某一种特定类型。
3、灵活性
开发者可以根据需要选择不同的枚举类型处理方式,比如使用名称(name())或顺序值(ordinal())进行转换。
属性
enumClassType
propertyType
java对象的属性类型
方法
public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType)
将枚举值设置为数据库参数。在执行 SQL 语句前调用此方法,将枚举的值转换为相应的数据库类型并设置到 PreparedStatement 中。
public E getNullableResult(CallableStatement cs, int columnIndex)
public E getNullableResult(ResultSet rs, String columnName)
从结果集中获取列值并转换为相应的枚举类型。如果列值为 null,则返回 null。
public E getNullableResult(ResultSet rs, int columnIndex)
用于通过列索引获取列值并转换为枚举类型。
使用场景
1、数据库表中存储枚举值
当你有一个数据库表列用于存储枚举类型时,可以使用 MybatisEnumTypeHandler 进行转换。例如,有一个订单状态的枚举,存储在数据库的字符串或整型字段中。
2、查询并映射枚举类型
当从数据库中查询数据时,使用 MybatisEnumTypeHandler 可以将数据库中的字符串或整型值自动转换回 Java 中的枚举类型。
BoundSql
基本概念
在 MyBatis 中,BoundSql 类是一个重要的组件,用于表示与 SQL 相关的信息。它主要用于将 SQL 语句及其参数绑定在一起,以便于执行和映射。
作用
1、封装 SQL 信息
BoundSql 封装了最终要执行的 SQL 语句及其参数。它负责存储和提供 SQL 语句以及相关参数的信息。
2、参数映射
BoundSql 支持将参数映射到 SQL 语句中,这对于动态 SQL 和处理复杂的 SQL 语句非常重要。它允许开发者灵活地构建 SQL 语句并将参数应用于其中。
3、支持动态 SQL
在处理动态 SQL 时,BoundSql 可以动态生成 SQL 语句和参数,从而支持更复杂的查询逻辑。
属性
sql
存储最终执行的 SQL 语句,可以是经过解析和处理后的 SQL。
parameterMappings
存储 SQL 语句中参数的映射信息。这些映射信息定义了 SQL 语句中参数的位置和类型。
parameterObject
传递给 SQL 语句的参数对象。这个对象可能是一个普通 Java 对象或 Map 等,具体取决于实际的参数类型。
使用场景
1、执行 SQL 语句: 在执行 SQL 时,BoundSql 将 SQL 语句和参数组合在一起,供 MyBatis 执行器使用。
2、动态 SQL 处理: 当使用动态 SQL 生成器时,BoundSql 可以帮助将动态生成的 SQL 语句与参数进行绑定,从而实现复杂的查询。
3、缓存机制: 在 MyBatis 的缓存机制中,BoundSql 也扮演着重要角色,帮助缓存执行的 SQL 及其结果。
Invocation
基本概念
Invocation 类在 MyBatis 插件开发中扮演着重要的角色,它是插件执行过程中用于封装方法调用信息的对象。
源码
作用
1、封装调用信息
Invocation 类包含了被拦截的方法信息,包括目标对象、方法名称、参数等。通过这个类,开发者可以获取关于当前方法调用的详细信息。
2、调用原方法
Invocation 提供了 proceed() 方法,用于执行被拦截的方法。这使得插件在执行自定义逻辑后,可以选择继续调用原有的方法或进行替代。
属性
target
指向被拦截的目标对象。开发者可以通过这个属性访问目标对象,从而进行必要的操作。
method
表示被拦截的方法对象,可以通过它获取方法的名称、参数类型等信息。
args
一个数组,包含了被拦截方法的参数。开发者可以根据这些参数进行相应的处理。
方法
proceed()
该方法用于继续执行原方法。如果需要在自定义逻辑执行后调用原方法,可以使用这个方法。
示例代码
总结
Invocation 类在 MyBatis 插件开发中用于封装方法调用的相关信息,提供了对目标对象、方法及参数的访问。它的 proceed() 方法允许开发者在自定义逻辑后继续执行被拦截的方法。理解和利用 Invocation 的功能,可以帮助开发者编写灵活且强大的 MyBatis 插件。
PropertyTokenizer
基本概念
源码
方法
public PropertyTokenizer(String fullname)
根据给定的属性字符串创建一个 PropertyTokenizer 实例。
public String getName()
获取当前解析的属性名称。
public String getIndexedName()
如果当前属性是一个索引或集合,会返回带有索引的属性名称。如果当前属性没有索引,那么返回属性的名称。
public boolean hasNext()
检查是否还有下一个属性可供解析。
public PropertyTokenizer next()
返回下一个属性标记器
public String getChildren()
返回直接的下一个属性
主要功能
1、解析属性字符串
PropertyTokenizer 可以将一个完整的属性路径分解为多个组成部分,通常是对象的属性名称和索引。这使得可以轻松地处理嵌套属性和集合。
2、支持集合和数组
在解析过程中,PropertyTokenizer 能够识别并处理集合(如 List 或 Map)中的元素以及数组的索引,这对于动态访问复杂数据结构很有帮助。
3、便于动态访问
通过将属性路径分解,开发者可以更灵活地访问和操作对象的属性,尤其是在编写动态 SQL 或实现 ORM 映射时。
代码示例
假设我们有一个复杂的对象结构,称为 User,它包含 Address 对象
我们想要解析属性路径 address.street,可以使用 PropertyTokenizer
总结
PropertyTokenizer 类在 MyBatis 中扮演着重要的角色,简化了对复杂属性路径的解析和处理。它提供了一种高效的方式来动态访问对象的嵌套属性和集合,极大地方便了 ORM 映射和动态 SQL 的生成与执行。理解 PropertyTokenizer 的工作原理,有助于开发者更好地利用 MyBatis 进行数据库操作。
EnumTypeHandler
基本概念
EnumTypeHandler是MyBatis中默认的枚举类型处理器,用于处理枚举类型与数据库之间的转换。
源码
作用
1、存储时:将枚举的名称存入数据库
2、读取时:将数据库中的字符串转换为对应的枚举
工作原理
使用EnumTypeHandler时:
存储:Sex.MALE → 数据库存储为字符串 "MALE"
读取:数据库的 "MALE" → 转换为 Sex.MALE
默认行为
1、MyBatis 默认使用此处理器处理所有枚举类型
2、无需额外配置,开箱即用
数据库字段要求
1、字段类型必须是字符串类型(VARCHAR、TEXT等)
2、字段长度要足够存储枚举名称
优点
1、数据库存储直观易读
2、代码可读性强
缺点
1、占用存储空间较大
2、枚举名称变更会影响数据
总结
EnumTypeHandler适合对数据可读性要求高、枚举名称相对稳定的场景。
EnumOrdinalTypeHandler
基本概念
EnumOrdinalTypeHandler 是 MyBatis 内置的枚举类型处理器,专门处理枚举与数据库数值的映射关系。
源码
核心功能
将枚举的序号(ordinal)与数据库的整型字段相互转换。
工作原理
1、Java → 数据库
2、数据库 → Java
使用方式
注解配置
优点
1、存储空间小(整型)
2、查询性能好
3、数据库友好
缺点
1、可读性差(数据库看到的是数字)
2、维护风险高(调整枚举顺序会破坏数据)
3、调试困难
最佳实践
1、固定枚举顺序 - 一旦定义,不要调整枚举项的顺序
2、谨慎新增 - 只在末尾添加新枚举项
3、文档记录 - 明确记录每个序号的含义
4、考虑替代方案 - 业务场景复杂时建议使用 EnumTypeHandler(存储枚举名称)
TypeHandlerRegistry
基本概念
TypeHandlerRegistry 是 MyBatis 的类型处理器注册中心,负责管理所有 TypeHandler 的注册、查找和调用。
源码
核心职责
1、类型处理器注册
2、处理器查找
1、根据 Java类型 + JDBC类型 查找合适的处理器
2、支持继承关系查找(父类、接口)
3、提供默认处理器兜底
工作流程
1、注册阶段(启动时)
2、查找阶段(执行时)
注册方式
1、自动扫描注册
2、手动注册
查找策略
优先级顺序:
1、精确匹配:Java类型 + JDBC类型都匹配
2、Java类型匹配:只匹配Java类型,JDBC类型为空
3、JDBC类型匹配:只匹配JDBC类型,Java类型为空
4、继承关系查找:查找父类、接口的处理器
5、默认处理器:使用 UnknownTypeHandler
总结
TypeHandlerRegistry 确保了类型转换的统一管理和高效查找,是 MyBatis 类型系统的核心组件。
StdOutImpl
基本概念
StdOutImpl是MyBatis中最简单的日志输出实现类,用于将SQL执行日志直接输出到控制台。
源码
核心特征
1、包路径
org.apache.ibatis.logging.stdout.StdOutImpl
2、输出方式
使用System.out.println()直接打印到控制台
3、实现接口
实现了MyBatis的Log接口
主要作用
1、开发调试
在开发环境快速查看SQL执行情况
2、简单配置
无需额外日志框架配置,开箱即用
3、临时使用
适合临时调试和测试场景
配置方式
Spring Boot YAML配置
输出效果
优点
1、配置简单,立即生效
2、无需额外依赖
3、适合快速调试
缺点
1、只能输出到控制台,无法保存到文件
2、无法控制日志级别
3、生产环境不适用
4、性能开销相对较大
使用场景
1、开发环境
快速查看SQL执行情况
2、单元测试
验证SQL生成是否正确
3、问题排查
临时开启查看具体执行的SQL
注意事项
1、生产环境慎用:会产生大量控制台输出
2、性能影响:频繁的IO操作会影响性能
3、日志管理:无法进行日志级别控制和文件管理
总结
StdOutImpl是MyBatis提供的最基础的日志实现,适合开发阶段快速查看SQL执行情况,但不建议在生产环境使用。
NoLoggingImpl
基本概念
NoLoggingImpl 是 MyBatis 框架中的一个日志实现类,它位于
org.apache.ibatis.logging.nologging 包中。这个类的主要作用是提供一个不执行任何日志记录操作的日志实现。
源码
核心功能
1、禁用日志输出
当配置 MyBatis 使用 NoLoggingImpl 时,所有的 SQL 语句执行、参数绑定等日志信息都不会被输出
2、空实现模式
遵循了"空对象模式"的设计模式,提供了日志接口的所有方法实现,但这些方法内部不执行任何实际操作
3、性能优化
在不需要日志的生产环境中使用,可以减少日志处理的性能开销
实现细节
NoLoggingImpl 类实现了 MyBatis 的 Log 接口,但所有的日志方法(如 debug、trace、warn 等)都是空实现。
使用场景
1、生产环境
在生产环境中,为了最大化性能,不需要输出详细的 SQL 日志
2、性能测试
进行性能测试时,需要排除日志记录对性能的影响
3、特定模块静默
对于某些不需要日志的特定模块,可以单独配置使用 NoLoggingImpl
4、敏感数据处理
处理敏感数据时,可能不希望将 SQL 语句和参数记录到日志中
配置方式
在 MyBatis-Spring 或 MyBatis-Spring-Boot 中配置
通过代码配置
欢迎大家关注我,持续带你们一起努力进步。