【gpcopy源码】【扑牛神器源码】【免费领取前端源码】resultmap源码解析

1.MyBatis-Plus中如何使用ResultMap
2.MyBatis 码解源码解析:映射文件的加载与解析(上)
3.SpringBoot系列 Mybatis 之自定义类型转换 TypeHandler
4.Mybatis源码剖析(懒加载原理)
5.2万多行MyBatis源码,你知道里面用了多少种设计模式吗?
6.Mybatis 码解TypeHandler(类型处理器)转换参数到SQL和转换SQL查询结果到Java类

resultmap源码解析

MyBatis-Plus中如何使用ResultMap

       MyBatis-Plus 对 MyBatis 基本零侵入,完全可以与 MyBatis 混合使用,这点很赞。

        在涉及到关系型数据库增删查改的业务时,我比较喜欢用 MyBatis-Plus ,开发效率极高。具体的使用可以参考官网,或者自己上手摸索感受一下。

        下面简单总结一下在 MyBatis-Plus 中如何使用 ResultMap 。

        先看个例子:

        有如下两张表:

        其中, tb_hero 中的 bid 关联 tb_book 表的 id 。

        下面先看 Hero 实体类的代码,如下:

        注意了,我特地把 tb_hero 表中的 bid 字段映射成实体类 Hero 中的 bookId 属性。

        MyBatis-Plus 打印出的 SQL 为:

        没毛病, MyBatis-Plus 会根据 @TableField 指定的映射关系,生成对应的 SQL 。

        MyBatis-Plus 打印出的 SQL 为:

        也没毛病,可以看到生成的 SELECT 中把 bid 做了别名 bookId 。

        比如现在我想连接 tb_hero 与 tb_book 这两张表,如下:

        查询 MyBatis-Plus 打印出的 SQL 为:

        SQL没啥问题,过滤与分页也都正常,但是此时你会发现 bookId 属性为 null ,如下:

        为什么呢?

        调用 BaseMapper 中内置的 selectById() 方法并没有出现这种情况啊???

        回过头来再对比一下在 HeroMapper 中自己定义的查询与 MyBatis-Plus 自带的 selectById() 有啥不同,还记得上面的刚刚的测试吗,生成的SQL有啥不同?

        原来, MyBatis-Plus 为 BaseMapper 中内置的方法生成SQL时,会把 SELECT 子句中 bid 做别名 bookId ,而自己写的查询 MyBatis-Plus 并不会帮你修改 SELECT 子句,也就导致 bookId 属性为 null 。

        在这里就是 tb_hero 表中的 bid 字段映射成实体类 Hero 中的 bid 属性。这样当然可以解决问题,但不是本篇讲的重点。

        在 @TableName 设置 autoResultMap = true

        然后在自定义查询中添加 @ResultMap 注解,如下:

        这样,也能解决问题。

        下面简单看下源码, @ResultMap("mybatis-plus_实体类名") 怎么来的。

        详情见: com.baomidou.mybatisplus.core.metadata.TableInfo#initResultMapIfNeed()

        注意看上面的字符串 id 的构成,你应该可以明白。

        思考: 这种方式的 ResultMap 默认是强绑在一个 @TableName 上的,如果是某个聚合查询或者查询的结果并非对应一个真实的表怎么办呢?有没有更优雅的方式?

        基于上面的思考,我做了下面简单的实现:

        关键代码其实没有几行,耐心看下应该不难懂。

        还是用例子来说明更直观。

        下面是一个聚合查询:

        其中 BookAgg 的定义如下,在实体类上使用了 @AutoResultMap 注解:

MyBatis 源码解析:映射文件的加载与解析(上)

       MyBatis 的映射文件是其核心组成部分,用于配置 SQL 语句、码解二级缓存及结果集映射等功能,码解是码解其区别于其他 ORM 框架的重要特色。

       在解析映射文件时,码解gpcopy源码MyBatis 码解通过调用 XMLMapperBuilder#parse 方法实现加载与解析操作。此方法首先判断映射文件是码解否已解析,若未解析则调用 XMLMapperBuilder#configurationElement 方法解析所有配置,码解并注册当前映射文件关联的码解 Mapper 接口。对于处理异常的码解标签,MyBatis 码解会记录至 Configuration 对象并尝试二次解析。

       解析流程主要涉及以下几个关键步骤:

       缓存配置(cache 标签):MyBatis 码解采用缓存设计,分为一级缓存和二级缓存。码解解析 cache 标签时,码解首先获取相关属性配置,然后使用 CacheBuilder 创建缓存对象,并记录到 Configuration 对象。

       缓存引用(cache-ref 标签):标签默认限定在 namespace 范围内,用于引用其它命名空间中的缓存对象。解析过程中记录引用关系,然后从 Configuration 中获取引用的缓存对象。

       结果集映射(resultMap 标签):解析 resultMap 标签配置,构建 ResultMap 对象,并将其记录到 Configuration 中。扑牛神器源码

       SQL 语句(sql 标签):通过 sql 标签配置复用的 SQL 语句片段,解析后记录至 Configuration 的 sqlFragments 属性中。

       核心数据库操作(select / insert / update / delete 标签):解析这些标签时,构建 MappedStatement 对象并记录到 Configuration 中。

       每个标签解析实现由 MyBatis 提供的多个方法执行,如 XMLMapperBuilder 的 configurationElement 方法和解析具体标签的子方法,如 cacheElement、sqlElement 等。解析过程中,MyBatis 会调用不同的构造器和工厂方法来创建、初始化和配置相应的对象。

       在解析完成之后,MyBatis 将所有配置对象封装在 Configuration 对象中,该对象包含所有映射文件中定义的配置信息,供后续的 SQL 语句执行和映射操作使用。

SpringBoot系列 Mybatis 之自定义类型转换 TypeHandler

       在使用 Mybatis 进行数据库操作时,我们常常遇到将数据库字段映射至 Java Bean 的需求。通常,我们通过 ResultMap 标签实现这一过程,指定两者之间的绑定关系。然而,当 Java Bean 中的字段类型与数据库中不同,如数据库为 timestamp 而 Java Bean 中定义为 long 时,应该如何处理呢?本文将深入探讨 Mybatis 免费领取前端源码中的自定义类型转换 TypeHandler,以解决这一问题。

       ### 环境准备

       本例采用 MySQL 作为数据库实例。首先,需创建一张包含 timestamp 类型字段的表。

       接着,使用 SpringBoot 2.2.1.RELEASE、maven 3.5.3 和 IDEA 进行项目开发。以下为相关依赖配置及 application.yml 配置信息。

       ### 实例演示

       在实体类(Entity)中定义字段时,确保与数据库表字段类型保持一致。例如,使用 timestamp 类型。

       定义 Mapper 接口时,使用注解方式实现简单的查询接口。需要注意的是,虽然 XML 和注解方式的实现差异不大,但使用注解更加简洁。

       ### 类型转换

       为了处理 Java Bean 与数据库类型之间的不一致,自定义 TypeHandler 是关键步骤。这通常涉及继承 BaseTypeHandler 类,并为 Java Bean 的类型定义泛型。

       ### TypeHandler 注册

       自定义 TypeHandler 后,如何让其生效是接下来需要解决的问题。通常,天盾导入源码有以下几种注册方式:通过 Result 标签指定、全局配置 SqlSessionFactory、全局 XML 配置或在 SpringBoot 配置文件中指定。

       1. **Result 标签中指定**:在 XML 配置中,通过 Result 标签中的 typeHandler 属性指定 TypeHandler。

        - XML 方式示例:

        xml

       - 注解方式示例:

        java

        @Result(column = "COLUMN_NAME", property = "PROPERTY_NAME", typeHandler = MyTypeHandler.class)

       2. **SqlSessionFactory 全局配置**:对于希望全局生效的 TypeHandler,可在 SqlSessionFactory 的配置中实现。

        - 示例配置:

        java

        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));

       3. **全局 XML 配置**:借助 mybatis-config.xml 配置文件注册 TypeHandler。需要在 SpringBoot 配置中指定相关配置以确保生效。

       4. **SpringBoot 配置方式**:通过指定 `type-handlers-package` 配置项注册 TypeHandler。

       ### 小结

       本文主要介绍了如何在 Mybatis 中处理数据库字段与 Java Bean 类型不一致的情况,通过自定义 TypeHandler 实现类型转换。自定义 TypeHandler 的注册方式多样,包括精确指定、全局生效等。

       本文还提到了 Mybatis 配置文件中的驼峰与下划线互转配置,这是一个常见的配置需求。此外,对于如何实现自定义的 name 映射,读者可以参考相关源码和知识点,或在社区寻求帮助。

       ### 不能错过的源码和相关知识点

       深入研究 Mybatis 的源码,了解 TypeHandler 的实现细节,对理解其工作原理大有裨益。地量量化源码同时,关注一灰灰 Blog 中的相关内容,可以获取更多学习资源和实战经验分享,促进个人技能提升。

Mybatis源码剖析(懒加载原理)

       懒加载,即按需加载,旨在优化查询性能。以一个包含订单列表的User对象为例,当仅获取用户信息时,若启用懒加载模式,执行SQL不会查询订单列表。需获取订单列表时,才会发起数据库查询。实现方式包括在核心配置文件中设置或在相关映射文件中通过fetchType属性配置懒加载策略。

       懒加载的配置如何加载到项目中呢?首先,这些配置保存在全局Configuration对象中,通常在解析核心配置文件的代码中实现。在settingsElement方法中,懒加载配置被保存在lazyLoadingEnabled属性中。对于resultMap标签中collection | association的fetchType属性,其配置通过解析mappers标签下的resultMap标签实现,最终调用buildResultMappingFromContext方法处理子标签。该方法结合全局配置判断是否需要执行懒加载。

       懒加载的实现原理涉及动态代理。当调用代理对象的延迟加载属性方法时,如访问a.getB().getName(),代理对象会调用拦截器方法。若发现需要延迟加载,代理对象会单独发送SQL查询关联对象,加载数据后设置属性值,完成方法调用。简而言之,懒加载通过动态代理实现,拦截指定方法并执行数据加载。

       深入剖析懒加载源码,会发现它涉及查询和数据处理的多步操作。查询完成后,结果集处理、列值获取、判断是否进行懒加载等步骤共同构建懒加载机制。动态代理在访问对象属性时触发,最终通过Javassist库创建代理对象,实现懒加载逻辑。当访问如userList2.get(0).getOrderList()时,若满足条件,代理对象会调用懒加载查询方法获取数据。判断懒加载条件的关键在于结果集处理阶段,通过访问映射关系和查询映射值来确定是否执行后续懒加载查询。

       综上所述,Mybatis的懒加载机制通过动态代理和结果集处理实现,旨在优化性能,按需加载数据,提高查询效率。通过核心配置和映射文件中的配置,懒加载逻辑被加载到项目中,为开发者提供灵活的加载策略。

2万多行MyBatis源码,你知道里面用了多少种设计模式吗?

       在MyBatis的两万多行的框架源码中,设计模式的巧妙使用是整个框架的精华。

       MyBatis中主要使用了以下设计模式:工厂模式、单例模式、建造者模式、适配器模式、代理模式、组合模式、装饰器模式、模板模式、策略模式和迭代器模式。

       具体来说,工厂模式用于SqlSessionFactory的创建,单例模式用于Configuration的管理,建造者模式用于ResultMap的构建,适配器模式用于统一日志接口,代理模式用于MapperProxy的实现,组合模式用于SQL标签的组合,装饰器模式用于二级缓存操作,模板模式用于定义SQL执行流程,策略模式用于多类型处理器的实现,迭代器模式用于字段解析的实现。

       通过运用这些设计模式,MyBatis成功地实现了复杂场景的解耦,并将问题合理切割为若干子问题,以提高理解和解决的效率。

       总的来说,MyBatis大约运用了种左右的设计模式,这使得框架在处理复杂问题时能够更加高效和灵活。

       学习源码不仅可以帮助我们更好地理解设计模式和设计原则,更能够扩展我们的编码思维,积累实际应用的经验。

       希望本文的分享能够帮助到您,同时也推荐您阅读《手写MyBatis:渐进式源码实践》一书,了解更多关于MyBatis的知识。

Mybatis TypeHandler(类型处理器)转换参数到SQL和转换SQL查询结果到Java类

       TypeHandler在Mybatis中的作用

       在预处理语句(PreparedStatement)中设置参数或从结果集中取出值时,TypeHandler负责将获取的值以合适的方式设置到PreparedStatement,或转换成Java类型。通过重写TypeHandler或创建自己的TypeHandler,可以处理不支持的或非标准类型。

       在项目中,对于只有有限个值的字段,常使用数字类型表示,如考试状态字段exam_status定义为tinyint。在代码中直接使用Integer表示时,读性和维护性较差,故定义枚举类来表示。需要实现TypeHandler以自动完成从数据库数字类型转换成枚举类的过程。

       实现TypeHandler的方案如下:定义枚举类实现EnumBase接口,包含codeOf静态方法进行数字转换。然后创建TypeHandler类实现org.apache.ibatis.type.TypeHandler接口,重写相应方法。避免在xml配置文件为每个枚举单独声明TypeHandler,使用Java代码动态注册,关键在于配置类。

       Mybatis注册工厂TypeHandlerRegistry初始化常见类型转换器,如String类型。执行转换时,通过TypeHandlerRegistry获取TypeHandler。自定义枚举类能起作用,依据TypeHandlerRegistry获取TypeHandler的顺序。Mybatis使用TypeHandler实现参数设置到SQL和转换SQL查询结果到Java类的过程。

       在mapper文件中,所有parameter入参的Java参数关联TypeHandler,解析成ParameterMapping对象,其中每条SQL的parameter入参关联UnknownTypeHandler,因为字段未指定JavaType和jdbcType属性,只有指定parameterType属性,Mybatis才能获取实际Java类型。resultMap的Java参数也关联TypeHandler,通过type属性获取实际Java类型并关联TypeHandler。

       执行代码时,SQL参数设置和查询结果转换到Java类的过程由TypeHandler完成。对于参数设置,调用TypeHandler设置SQL参数,获取真正TypeHandler是通过TypeHandlerRegistry.getTypeHandler方法实现。转换查询结果到Java类的过程复杂,由DefaultResultSetHandler处理。

       了解Mybatis执行流程有助于深入理解TypeHandler的作用和实现细节。建议实际项目中实践TypeHandler的使用,提高代码的可读性和可维护性。

       TypeHandler源码地址:[提供源码GitHub链接]

更多内容请点击【百科】专栏

精彩资讯