随手集☞mybatis知识盘点

本文围绕MyBatis展开,先指出传统JDBC开发问题及MyBatis的解决办法,介绍ORM定义与常见框架,阐述MyBatis作为半自动ORM工具的特点。还深入剖析其底层原理、架构设计、映射器使用等,涵盖分页、动态SQL等内容,最后解答相关使用问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

背景

传统的JDBC开发有什么问题

  • 频繁创建数据库连接对象,释放对象,容易造成系统资源浪费,影响系统性能
  • sql语句定义参数设置,耦合度较高,如果涉及参数修改,则需要重新修改Java代码,系统就需要重新编译,重新发布。代价较高
  • 结果集处理存在重复代码,处理麻烦

mybatis如何处理jdbc的通病

数据库连接创建,频繁的释放会影响系统的性能问题,mybatis-config.xml 中配置 数据连接池,使用连接池管理数据库的连接

  1. SQL语句写在代码中造成代码不易维护

    • 解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离
  2. 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参
    数一一对应。

    • 解决: Mybatis自动将java对象映射至sql语句。
  3. 结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装
    成pojo对象解析比较方便。

    • 解决:Mybatis自动将sql执行结果映射至java对象。

ORM 定义

  • 对象关系映射,是一种为了解决关系型数据库数据与简单java对象 POJO 的映射关系的技术
  • 简单来说,ORM是通过使用描述对象数据库之间映射元数据,将程序中的对象自动持久化关系型数据库

熟知的ORM框架

  • Hibernate:
    • Hibernate是Java领域最著名的ORM框架之一。它提供了全功能的ORM实现,包括对象关系映射数据查询事务处理等。Hibernate支持多种数据库,并具有良好的扩展性和性能。
  • MyBatis:
    • MyBatis是另一个在Java领域广泛使用的ORM框架。与Hibernate相比,MyBatis更强调SQL的灵活性,它允许开发者编写原生SQL语句,并通过映射文件将结果映射为Java对象。MyBatis适合对SQL性能有较高要求的场景。
  • Entity Framework:
    • Entity Framework是.NET平台上的ORM框架。它提供了丰富的功能,包括数据模型设计查询变更跟踪等。Entity Framework支持LINQ(Language Integrated Query)查询,使得数据操作更加直观和简洁。

为什么说Mybatis是半自动ORM映射工具

MyBatis在SQL控制对象映射方面提供了较高的灵活性可控性。相较于全自动ORM工具,如Hibernate,MyBatis的主要特点体现在以下几个方面:

  1. SQL的明确控制
    • 在MyBatis中,开发人员可以直接书写SQL语句,通过绑定参数结果集映射来实现对象关系映射的功能。这种方式使得开发人员能够根据自己的需求和对性能的要求,编写高效的SQL语句。
    • 与此相比,全自动ORM工具如Hibernate则通常根据对象的属性自动生成SQL语句,这在某些复杂查询或性能要求较高的场景下可能存在一定的局限性。
  2. 对象映射的自定义
    • MyBatis将查询结果映射成Java对象,但不会自动建立对象之间的关系。开发者需要手动控制对象之间的关系,从而实现关系型数据库和面向对象程序的映射。这种方式更加的灵活性,使得开发者能够应对各种复杂的映射需求
    • 而全自动ORM工具则会自动处理这些映射关系。
  3. 延迟加载机制
    • MyBatis提供了延迟加载机制,这使得大量数据查询不会同时加载到内存中。当需要使用某个关联对象时,MyBatis才会通过代理模式实现对该对象的延迟加载。这种机制有助于优化性能,特别是在处理大量数据时。

半自动与全自动的区别在哪里?

  1. 灵活性
    • 全自动ORM:全自动ORM工具通常提供了较为固定映射方式查询机制,对于复杂查询映射需求可能存在一定的局限性。此外,由于自动生成的SQL语句可能不是最优的,因此在某些性能要求较高的场景下可能需要进行额外的优化
    • 半自动ORM:半自动ORM工具则允许开发者根据实际需求编写优化SQL语句,从而实现更高效的数据库操作。同时,由于开发者可以自定义映射关系,因此能够更好地处理复杂的数据结构和关系。
  2. 配置复杂性
    • 全自动ORM:全自动ORM工具通常通过注解或配置文件来定义实体类和映射关系,配置相对简单且直观
    • 半自动ORM:半自动ORM工具则需要开发者手动编写SQL语句和映射配置,配置过程相对繁琐
  3. 性能优化
    • 全自动ORM:全自动ORM工具在性能方面可能存在一定的局限性,自动生成的SQL语句可能不是最优的。由于高度抽象化的操作,可能在某些情况下导致额外的性能开销
    • 半自动ORM:半自动ORM工具允许开发者直接编写优化SQL语句,因此能够更好地控制性能。开发者可以根据实际需求进行索引优化批量操作性能提升措施。

mybatis 定义

MyBatis 是一个优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通的 Java 对象)为数据库中的记录。以下是 MyBatis 的主要优点和缺点:

  • 优点

    1. 灵活性:MyBatis 允许开发者直接编写 SQL 语句,这使得开发者能够根据自己的需求精确地控制数据库操作。无论是简单的 CRUD 操作还是复杂的查询,MyBatis 都能提供灵活的支持。

    2. 解耦:MyBatis 将 SQL 语句从== Java 代码分离出来,使得业务逻辑与数据库操作更加清晰==、易于维护。这有助于降低代码的耦合度,提高代码的可读性和可维护性。

    3. 性能优化:由于 MyBatis 允许开发者直接编写 SQL,因此可以更容易地进行性能优化。开发者可以根据实际需求进行索引优化批量操作等性能提升措施。

    4. 动态 SQL:MyBatis 提供了强大的动态 SQL 功能,可以根据不同的条件生成不同的 SQL 语句。这使得开发者能够更灵活地处理各种复杂的查询需求。

    5. 易于集成:MyBatis 可以与多种数据库和 Java Web 框架(如 Spring)进行集成,使得开发者能够更加方便地使用它进行数据库操作。

  • 缺点

    1. SQL 语句的编写和维护:虽然 MyBatis 提供了灵活的 SQL 编写方式,但同时也增加了 SQL 语句的编写和维护成本。开发者需要手动编写测试 SQL 语句,确保它们的正确性和性能

    2. 学习成本:对于初学者来说,学习 MyBatis 的配置和使用可能需要一定的时间和努力。尽管 MyBatis 的文档比较完善,但理解其核心概念和最佳实践仍然需要一定的实践经验

    3. 错误处理:由于 MyBatis 允许直接操作数据库,因此开发者需要更加注意错误处理。如果 SQL 语句编写不当数据库连接出现问题,可能会导致程序崩溃数据丢失

    4. XML 配置的复杂性:MyBatis 的 XML 配置虽然强大,但也可能变得相当复杂,特别是在大型项目中。管理和维护大量的 XML 文件可能会成为一个挑战。

底层原理

Mybatis的工作原理

在这里插入图片描述

MyBatis通过读取配置文件、构建SqlSessionFactory创建SqlSession使用执行器执行SQL命令映射处理以及返回结果等步骤,实现了对数据库的持久层操作。其工作原理充分利用了动态代理反射机制,使得开发者可以更加灵活和方便地进行数据库操作。

  1. 读取配置文件:MyBatis首先加载配置文件,包括全局配置文件(如SqlMapConfig.xml)和SQL映射文件(如Mapper.xml)。全局配置文件主要配置MyBatis的运行环境信息,如数据源、事务等;而SQL映射文件则配置与SQL执行相关的信息。
  2. 构建SqlSessionFactory:MyBatis通过读取这些配置文件的信息,构造出SqlSessionFactory,即会话工厂。SqlSessionFactory是MyBatis的核心类,它提供了创建SqlSession的方法。
  3. 创建SqlSession:通过SqlSessionFactory,MyBatis可以创建出SqlSession对象。SqlSession是一个接口,它包含了执行SQL命令所需的所有方法,如select、insert、update和delete等
  4. 执行器(Executor):由于SqlSession本身并不能直接操作数据库,因此它会使用一个执行器(Executor)来帮它执行操作。执行器会根据SqlSession提供的信息,生成对应的SQL语句,并通过JDBC等数据库驱动与数据库进行交互。
  5. 映射处理:MyBatis会根据映射文件中的配置,将查询结果映射Java对象,或者将Java对象转换为SQL语句。这一过程通过动态代理和反射机制实现。(MyBatis在映射处理时,可能会使用JDK动态代理或CGLIB代理,这取决于被代理的对象是接口还是类。)
  6. 返回结果:MyBatis将处理完的结果返回给调用者,完成整个数据库操作过程。
  • 简易版
    1. 读取mybatis配置文件,mybatis-config.xml加载运行环境和映射文件
    2. 构建会话工厂SqlSessionFactory
    3. 会话工厂创建SqlSession对象,包含了执行SQL语句的所有方法
    4. 操作数据库的接口,Executor执行器,同时负责缓存维护
    5. Executor接口的执行方法中有一个MappedStatement类型的参数,封装了映射信息
    6. 输入参数映射
    7. 输出结果映射

Mybatis是如何进行分页的?分页插件的原理是什么?

Mybatis进行分页主要依赖于分页插件,该插件通过拦截器的方式,在SQL执行前将分页参数(如当前页、每页显示的数据条数等)注入到SQL语句中,从而生成对应的分页SQL,实现分页查询。

  • 分页插件的核心类是PageInterceptor,其工作原理如下:

    1. 在Mybatis的配置文件中,添加PageInterceptor类,并设置相应的参数,如SQL ID、数据库类型以及分页SQL的分类方式(如正则表达式)等。
    2. 当查询请求经过SqlSessionFactory并关闭SqlSession时,会代理执行plugin.wrap方法,将当前分页拦截器注入Executor对象的链式调用中,拦截Query操作并按分页逻辑返回结果。
    3. 当Executor的查询操作触发时,PageInterceptor会拦截这个操作,并对查询语句进行重新构造,以符合分页的需求。具体来说,它会通过拼接limit和offset来实现翻页逻辑。
    4. 在分页插件的帮助下,Mybatis可以更加高效和灵活地处理分页查询。开发者只需要配置好分页插件,然后在编写SQL语句时无需关心分页逻辑,Mybatis会自动处理并生成相应的分页SQL。

注意:分页插件的实现原理可能因Mybatis版本的不同而有所差异。

Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理吗?

  • Mybatis动态SQL主要用于根据不同的条件动态生成SQL语句,实现灵活的条件查询和更新操作。通过动态SQL,开发者可以避免编写大量的固定SQL查询,而是根据实际需求构建可变的SQL语句,从而提高代码的重用性和灵活性,并减少SQL注入的风险。

  • Mybatis中提供了多种动态SQL标签,主要包括:

    • <where>: 用于在生成的SQL语句中添加WHERE子句,自动处理条件语句的前缀,并在有条件语句存在时添加WHERE关键字。
    • <set>: 用于在生成的SQL语句中添加SET子句。
    • <foreach>: 用于在生成的SQL语句中进行循环操作。
    • <if>: 用于在生成的SQL语句中添加条件判断。
    • <choose>, <when>, <otherwise>: 类似于Java中的switch语句,根据条件选择执行不同的SQL语句片段。
    • <bind>: 用于将表达式的结果绑定到一个变量上。
  • 执行原理

    • 基于解析XML映射文件和处理SQL语句的方式
      • 当Mybatis解析XML映射文件时,它会检测到包含动态SQL的语句,并将其转换为内部的数据结构(MappedStatement)
      • 在运行时,Mybatis会根据参数的值和配置的条件逻辑,动态构建最终的SQL语句
    • 这个过程包括解析XML映射文件,识别动态SQL标签,根据条件动态生成SQL语句,并执行生成的SQL语句。
  • 动态SQL采用了预编译的方式来拼接SQL语句,能够有效防止SQL注入攻击

简述Mybatis的插件运行原理,以及如何编写一个插件。

MyBatis的插件运行原理主要基于责任链模式(Chain of ResponsibilityPattern),允许开发者在MyBatis的核心处理流程中插入自定义的逻辑,从而在不修改MyBatis源代码的情况下扩展其功能。插件在MyBatis中的作用非常强大,几乎可以影响到MyBatis的任意行为。

  • 插件的运行原理如下

    • 插件加载与注册:在MyBatis初始化过程中,会加载注册插件。这个过程通常是通过配置文件中的标签来完成的。每个插件都需要实现Interceptor接口,并提供一个拦截器链(Interceptor Chain)中的位置信息。

    • 创建代理对象:当MyBatis需要执行某个操作时(如创建SqlSession、执行SQL语句等),它会检查是否存在针对该操作的插件。如果存在,MyBatis会使用动态代理技术为相关对象创建代理对象包装真实对象,并在调用真实对象的方法前后插入插件的逻辑。

    • 调用插件逻辑:当代理对象的方法被调用时,它会首先执行插件的intercept方法(执行自定义的逻辑,如修改参数、改变SQL语句等)。然后,插件会调用proceed方法继续执行原始操作

  • 责任链传递:如果有多个插件注册到同一个拦截点,它们会按照配置顺序形成一个责任链。当一个操作发生时,MyBatis会按照顺序依次调用每个插件的intercept方法,直到所有插件都执行完毕最后执行原始操作

  • 如何编写一个MyBatis插件

    1. 实现Interceptor接口:编写一个类实现MyBatis的Interceptor接口。这个接口定义了一个intercept方法,你需要在这个方法中编写你的自定义逻辑。

    2. 定义@Intercepts注解:在插件类上使用@Intercepts注解,并指定要拦截的方法。@Intercepts注解内部可以包含多个@Signature注解,每个@Signature注解代表一个拦截点。你需要指定拦截的方法类型(如Executor、StatementHandler等)、方法名以及参数类型。

    3. 编写自定义逻辑:在intercept方法中,你可以获取到被拦截方法的参数,并根据你的需求修改这些参数或者执行其他操作。最后,你需要调用proceed方法继续执行原始操作。

    4. 注册插件:在MyBatis的配置文件中使用标签注册你的插件。指定插件类的全限定名,并配置其他相关参数(如插件的属性)。

      • 插件示例:它会在执行SQL语句前打印出SQL内容:
      import org.apache.ibatis.executor.statement.StatementHandler;  
      import org.apache.ibatis.plugin.*;  
        
      import java.sql.Connection;  
      import java.util.Properties;  
        
      @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})  
      public class SqlPrintInterceptor implements Interceptor {  
        
          @Override  
          public Object intercept(Invocation invocation) throws Throwable {  
              StatementHandler statementHandler = (StatementHandler) invocation.getTarget();  
              String sql = statementHandler.getBoundSql().getSql();  
              System.out.println("执行的SQL语句是:" + sql);  
              return invocation.proceed();  
          }  
        
          @Override  
          public Object plugin(Object target) {  
              return Plugin.wrap(target, this);  
          }  
        
          @Override  
          public void setProperties(Properties properties) {  
              // 可以设置插件的属性,这里暂时不用  
          }  
      }
      

      在MyBatis的配置文件中注册这个插件:

      <configuration>  
          <!-- 其他配置 -->  
          <plugins>  
              <plugin interceptor="com.example.SqlPrintInterceptor">  
                  <!-- 如果插件有属性,可以在这里配置 -->  
              </plugin>  
          </plugins>  
      </configuration>
      

架构设计

MyBatis的功能架构

  • MyBatis的功能架构主要可以分为三层:

    • API接口层
      这一层主要提供外部使用接口API,开发人员通过这些本地API来操纵数据库
    • 数据处理层
      负责具体的SQL查找、SQL解析、SQL执行以及执行结果映射处理等。它的主要目的是根据调用请求完成一次数据库操作
    • 基础支撑层
      • 负责最基础功能支撑,包括连接管理、事务管理、配置加载和缓存处理
      • 类型转换模块日志模块
        • 类型转换模块主要负责Java类型JDBC类型之间的相互转换,这在SQL模板绑定用户传入实参的场景以及将ResultSet映射成结果对象时都有所体现。
        • 日志模块则用于集成Java生态中的第三方日志框架,如Log4j、Log4j2、slf4j等,以提供灵活的日志功能。

Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?

  • <resultMap>:定义结果集映射规则,将数据库查询结果Java对象属性进行映射

  • <parameterMap>:(已被弃用)用于定义参数映射,但在较新版本的MyBatis中,这个标签通常被省略,因为MyBatis可以自动处理大多数常见的参数类型。

  • <sql>:定义可重用的SQL片段,这些片段可以在其他的<select>、<insert>、<update><delete>标签中通过<include>标签引用。

  • <include>引用之前定义的<sql>标签中的SQL片段

  • <selectKey>:用于获取数据库生成的主键,特别是不支持自增主键的数据库。

  • 动态SQL标签:这些标签用于构建动态SQL语句,可以根据条件参数动态生成不同的SQL。

    • <choose>、<when>、<otherwise>:类似于Java中的switch-case结构,根据条件选择执行不同的SQL片段。
    • <trim>、<where>、<set>:对SQL片段进行前后空格或某些字符的去除、合并等操作,特别是处理SQL语句中的条件部分。
    • <if>:根据条件判断是否包含某个SQL片段。
    • <bind>绑定变量到上下文,供后续SQL使用。
    • <foreach>:用于处理集合类型的参数,通常用于IN查询。

Mybatis的一级、二级缓存

MyBatis 提供了一级缓存和二级缓存机制,优化了数据库访问性能,减少不必要的数据库查询。
在这里插入图片描述

  • 一级缓存
    也称为SqlSession 级别的缓存,它是默认开启的,并且不能关闭。一级缓存的作用域是一个 SqlSession,当在同一个 SqlSession 中执行两次相同的 SQL 语句时,第一次执行完毕会将结果放到缓存中,第二次查询时会从缓存中获取数据,而不是再次发送 SQL 到数据库。

    • 特点:

      • 生命周期:与 SqlSession 一致,当 SqlSession 关闭或清空时,一级缓存也会被清空
      • 缓存数据范围:只缓存同一个 SqlSession 中执行的 SQL 语句和结果
      • 缓存存储位置:在内存中,因此读取速度快。
    • 基于PerpetualCache的HashMap本地缓存,其缓存作用域为Session,当Session进行flush或close 之后,该Session中的所有Cache就将会被清空,默认打开一级缓存
      在这里插入图片描述

  • 二级缓存
    也称为 Mapper 级别的缓存,它可以跨多个 SqlSession,因此其作用域更大。多个SqlSession 可以共享一个二级缓存区域。需要手动开启,并且是针对namespace 进行的缓存,也就是针对 mapper 进行的缓存。不同的 mapper 查出的数据会放在自己对应的缓存区域中。

    • 特点

      • 生命周期与 namespace 绑定,只要 namespace 没有被销毁,缓存数据就存在。
      • 缓存数据范围跨多个 SqlSession,多个 SqlSession 可以共享二级缓存的数据。
      • 缓存存储位置默认是在堆内存中,但也可以配置成其他的存储方式,如 Redis、Memcached 等。
    • 基于namespace 和mapper的作用域起作用的,不是依赖于SqlSession默认也是采用PerpetualCache HashMap存储,需要单独开启,一个是核心配置,一个是mapper映射文件
      在这里插入图片描述

    • 二级缓存默认是关闭的

    • 开启方式

      • 全文配置文件
        <settings>
        	<settings name = "cacheEnabled" value = "true">
        </settings>
        
      • 映射文件
        使用<cache/>标签让当前mapper生效二级缓存
  • 使用注意事项

    1. 当 SqlSession 提交或回滚事务时,会清空一级缓存。
    2. 当执行增删改操作时,一级缓存和二级缓存都会被清空,因为增删改操作可能会影响到缓存中的数据一致性
    3. 二级缓存可能会导致脏读,因此在高并发场景下使用时需要谨慎,确保缓存数据的实时性和一致性
    4. 只有会话提交或者关闭之后,一级缓存中的数据才会转移到二级缓存中
    5. 在使用二级缓存时,建议对查询结果集进行序列化,以避免因对象不一致而导致的问题。
      • 如何开启二级缓存:在 MyBatis 的配置文件中,可以通过设置 <settings> 标签的 cacheEnabled 属性为 true 来开启二级缓存。同时,在需要缓存的 mapper XML 文件中,使用 标签来声明开启该 mapper 的二级缓存。
  • 总结
    MyBatis 的一级缓存和二级缓存机制可以有效地提高数据库访问性能,减少不必要的数据库查询。但在使用时需要注意缓存数据的一致性和实时性问题,以及在高并发场景下的潜在风险。

Mybatis都有哪些Executor执行器?它们之间的区别是什么?

  • SimpleExecutor(简单执行器):
    • 默认的执行器类型。它每次执行都会创建一个Statement对象,并立即执行SQL语句。
    • 不支持事务,每次都会关闭Statement对象,适用于简单的查询场景。
    • SimpleExecutor会进行两次预编译,每次都会构造一个PreparmentStatement对象,因此效率相对较低
  • ReuseExecutor(重用执行器):
    • 重用预处理的Statement对象,它会缓存Statement对象在map中,key为sql,value为Statement对象。
    • 当需要执行相同的SQL语句时,会直接使用缓存的Statement对象,而不是每次都创建新的对象。
    • 不支持事务。因此,执行相同的sql语句只会进行一次预编译,效率更高。
  • BatchExecutor(批处理执行器):
    • 这种执行器用于批量操作,可以一次执行多个SQL语句。执行update(JDBC批处理不支持select)时,会把所有sql添加到批处理中(addBatch()),等待统一批处理(executorBatch())。
    • 缓存了多个Statement对象,每一个Statement都是addBatch()后等待进行executorBatch()批处理。
    • BatchExecutor查询时与SimpleExecutor相同会进行多次编译,更新或删除时,会批量进行,需要手动提交

综上所述,三种执行器的主要区别在于它们处理SQL语句的方式和效率。

  • SimpleExecutor适用于简单查询场景,但效率相对较低
  • ReuseExecutor通过重用Statement对象提高了效率,但同样不支持事务
  • BatchExecutor则专注于批量操作,适用于大量数据处理场景。

Mybatis中如何指定使用哪一种Executor执行器?

在MyBatis中,执行器(Executor)的类型是由配置决定的,而不是直接在代码中指定的。

  • SIMPLE:这是MyBatis的默认执行器类型,它执行完一次update或select之后,会关闭Statement。

  • REUSE:执行器会重用预处理语句(PreparedStatement)。

  • BATCH:执行器会重复使用语句和批量更新,主要用于批量操作,减少了预处理语句的创建次数,提升了性能。

  • 实例:

    • MyBatis的配置文件(mybatis-config.xml)中设置默认的执行器类型。

      <settings>  
          <setting name="defaultExecutorType" value="REUSE"/>  
      </settings>
      
    • 通过编程方式动态地改变执行器的类型。例如,你可以通过SqlSessionFactory的openSession方法传递一个ExecutorType参数来指定所需的执行器类型。

      try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.REUSE)) {  
          // 在这个session中,MyBatis将使用REUSE类型的执行器  
          // ...  
      }
      

Mybatis延迟加载的实现原理是什么?

  • 延迟加载,也被称为懒加载,主要思想是在用到数据进行查询加载,不需要用到时不进行加载。这种策略可以提高程序的性能,节省系统资源,并避免数据重复加载。

在这里插入图片描述

  • 解析

    • 使用GCLIB动态代理创建目标对象的代理对象
    • 当调用目标方法时,进行拦截器invoke方法,发现目标方法是null值,执行sql查询
    • 获取数据之后,调用set方法设置属性值,再继续查询目标方法,就有值了
  • Mybatis的延迟加载主要是基于嵌套查询来实现的,具体实现原理如下:

    • 生成代理对象:当主对象(例如一个实体对象)被查询时,MyBatis会生成一个代理对象,这个代理对象包含了对关联对象的引用。

    • 触发时机:当访问代理对象中关联属性时,延迟加载机制会被触发。此时,MyBatis会拦截关联属性访问,并判断该属性是否已经被加载

      • 如果未加载,则触发新的SQL查询去加载该属性
      • 如果已加载,则直接返回该属性的值。
    • 填充数据:查询完成后,MyBatis会将查询到的数据填充到代理对象中,使得关联属性变得可用。

      MyBatis的动态代理机制是实现延迟加载的关键。通过动态代理,MyBatis能够在运行时生成代理对象,以拦截对关联属性的访问,并在需要时执行额外的查询。这样,系统就能够根据实际需求,智能地加载数据,避免在一开始就加载过多不必要的信息。

  • 配置使用

    • mybatis支持一对一关联对象和一对多关联集合对象的延迟加载
    • 在mybatis配置文件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false 默认是关闭的
      在这里插入图片描述
      在这里插入图片描述
  • 场景考虑
    大批量数据查询时,由于每次访问关联属性需要进行数据库查询,可能会消耗较多的时间,造成用户请求响应慢影响用户体验

    • 在一对多、多对多的关系中,通常推荐使用延迟加载;
    • 在一对一、多对一的关系中,可以考虑使用立即加载。

映射器

{}和${}的区别

  • 处理参数的方式:

    • #{}:MyBatis在处理时,会将SQL语句中的#{}替换为?,即占位符,然后使用PreparedStatement的set方法赋值
    • ${}:MyBatis在处理时,会直接将SQL语句中的${}替换参数的值
  • SQL注入问题:

    • 由于#{}预编译处理,因此它不会出现通过SQL注入改变SQL语句结构的问题。
    • ${}直接替换,所以可能会出现SQL注入的问题。
  • 使用场景:

    • #{}适用于大多数情况,特别是当参数是基本数据类型对象属性时。
    • ${}则主要用于一些特殊场景,如动态表名、列名等。因为在这些情况下,预编译处理可能无法正确识别处理这些动态元素

mapper中如何传递多个参数

  1. 使用 @Param 注解
    使用 @Param 注解来标识每个参数。在 XML 映射文件中,通过参数名来引用这些参数。

    • Mapper 接口示例:
    public interface UserMapper {  
        User selectUserByIdAndName(@Param("id") int id, @Param("name") String name);  
    }
    
    • XML 映射文件示例:
    <select id="selectUserByIdAndName" resultType="User">  
        SELECT * FROM user WHERE id = #{id} AND name = #{name}  
    </select>
    
  2. 使用 Map 传递参数
    创建一个 Map 对象,将多个参数作为键值对放入其中,然后传递给 Mapper 方法。

    • Mapper 接口示例:
    public interface UserMapper {  
        User selectUser(Map<String, Object> params);  
    }
    
    • XML 映射文件示例:
    <select id="selectUser" resultType="User">  
        SELECT * FROM user WHERE id = #{id} AND name = #{name}  
    </select>
    
  3. 使用自定义类型
    创建一个自定义的 Java 类型,将多个参数封装到这个类型中,然后在 Mapper 接口和 XML 映射文件中使用这个类型。

    • 自定义类型示例:
    public class UserSearchCriteria {  
        private int id;  
        private String name;  
        // getters and setters  
    }
    
    • Mapper 接口示例:
    public interface UserMapper {  
        User selectUser(UserSearchCriteria criteria);  
    }
    
    • XML 映射文件示例:
    <select id="selectUser" resultType="User">  
        SELECT * FROM user WHERE id = #{id} AND name = #{name}  
    </select>
    
  4. 使用 @Param 和自定义类型结合
    可以将 @Param 注解和自定义类型结合使用,在 XML 映射文件中既使用自定义类型,又使用单独的参数。

    • Mapper 接口示例:
    public interface UserMapper {  
        User selectUserWithCustomAndParam(@Param("criteria") UserSearchCriteria criteria, @Param("extraParam") String extraParam);  
    }
    
    • XML 映射文件中
      • 通过 #{criteria.id} 引用自定义类型中的属性
      • 通过 #{extraParam} 引用单独的参数。
  • 综合分析
    • @Param 注解通常是最简单直接的方式,
    • 使用自定义类型则可以在复杂的查询中提供更好的封装和组织

具体操作

mybatis 编程的步骤

MyBatis 编程的核心是创建 SqlSessionFactory、SqlSession,然后通过 Mapper 接口执行 SQL 语句。在此基础上,可以根据实际需求进行扩展和优化。

  1. 创建 SqlSessionFactory:这是MyBatis的核心配置,它包含数据库连接池信息和MyBatis系统核心设置等。创建 SqlSessionFactory 的方式是通过 SqlSessionFactoryBuilder 从 XML 配置文件(或使用 Java API 编程方式)中构建出 SqlSessionFactory 实例。
  2. 创建 SqlSession:SqlSession 是应用程序与数据库交互可重用线程安全接口。它是执行命令、获取映射器实例和获取事务管理器的核心接口
  3. 获取 Mapper:Mapper 是 MyBatis 中最重要的组件之一,它是由 Java 接口和 XML 文件(或注解)共同组成的。Mapper 接口的全限名要和 XML 文件中的 namespace 一致,接口中的方法名和 XML 文件中的 statement 的 id 一致,这样 MyBatis 才能找到并执行对应的 SQL 语句。
  4. 执行 SQL:通过 Mapper 接口的方法执行 SQL 语句,MyBatis 会根据接口方法名和 XML 文件中的配置找到对应的 SQL 语句并执行,然后返回结果。
  • 注意事项:

    1. 确保数据库驱动已正确添加至项目中,并配置了正确的数据库连接信息
    2. 在 XML 配置文件中,需要正确配置== mapper 映射文件位置==,以便 MyBatis 能找到加载它们。
    3. 使用注解或 XML 配置 SQL 语句时,要确保 SQL 语句正确性,并防止SQL 注入等安全问题。
    4. 对于复杂的 SQL 语句或查询逻辑,建议使用XML 配置方式,因为这种方式更具灵活性和可读性。

如何执行批量操作

  1. 配置MyBatis以使用BATCH执行器(两种方式)

    • 在MyBatis的配置文件(mybatis-config.xml)中,可以设置默认的执行器类型为BATCH:

      <settings>  
          <setting name="defaultExecutorType" value="BATCH"/>  
      </settings>
      
    • 在创建SqlSession时,可以显式地指定ExecutorType.BATCH:

      try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {  
          // 执行批量操作  
      }
      
  2. 编写Mapper接口和映射文件
    在Mapper接口中定义批量插入、更新或删除的方法。然后,在映射文件中编写相应的SQL语句。

    • 定义一个批量插入的方法:
    public interface UserMapper {  
        void insertUsers(List<User> userList);  
    }
    
    • 在映射文件(UserMapper.xml):
    <mapper namespace="com.example.mapper.UserMapper">  
        <insert id="insertUsers" parameterType="list">  
            INSERT INTO user (id, name, age)  
            VALUES   
            <foreach collection="list" item="user" separator=",">  
                (#{user.id}, #{user.name}, #{user.age})  
            </foreach>  
        </insert>  
    </mapper>
    
    • 执行批量操作
      使用SqlSession调用Mapper接口中定义的批量操作方法,并传入包含多个实体的列表。
    try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {  
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);  
        List<User> userList = // ... 填充用户列表 ...  
        userMapper.insertUsers(userList);  
        // 提交事务以执行所有批量操作  
        sqlSession.commit();  
        // 清除缓存,这一步是可选的,取决于你的配置和需要  
        sqlSession.clearCache();  
    }
    
    • 注意:在执行完所有批量操作后,需要调用sqlSession.commit()来提交事务,以确保所有的更改都被保存到数据库中。如果你使用的是自动提交模式(即每个语句执行后都自动提交),则不需要显式调用commit()方法。

    • sqlSession.clearCache()用于清除MyBatis的一级缓存,这在某些情况下可能是必要的,以确保后续查询不会返回旧的或已删除的数据。但是,这取决于你的具体需求和MyBatis的配置。

MyBatis中批量操作的优缺点是什么

  • 优点

    • 性能提升:批量操作通过减少数据库交互次数,显著提高了性能。传统的逐条插入或更新操作需要多次与数据库通信,而批量操作可以一次性发送多条SQL语句到数据库执行,减少网络传输开销数据库处理的次数

    • 资源利用:批量操作减少了数据库连接的建立关闭次数,从而提高了资源的利用效率。这对于需要处理大量数据的应用程序尤为重要。

    • 事务处理:在批量操作中,所有操作都在同一个事务中执行,这有助于保证数据的一致性和完整性。通过事务的控制,可以确保批量操作要么全部成功,要么全部失败避免了部分成功导致的数据不一致问题。

  • 缺点

    • 内存消耗:批量操作通常需要在内存中积累一定数量的数据后才进行批量处理。这可能会增加内存消耗,特别是在处理大量数据时,需要更多的内存来存储待处理的数据。

    • 错误处理:批量操作在出现错误时可能难以定位具体的问题所在。由于多个操作打包在一起执行,一旦出错,可能难以确定是哪个操作导致了问题。这增加了错误排查和处理的难度。

    • SQL语句长度限制:某些数据库可能对单个SQL语句长度有限制。如果批量操作生成的SQL语句过长,可能会超过数据库限制,导致操作失败

    • 不适合小量数据:对于少量的数据操作,使用批量操作可能并不会带来明显的性能提升,反而可能由于额外内存消耗和错误处理复杂性而得不偿失。

  • 总结:

    • 对于大量数据的处理,批量操作通常是一个很好的选择;
    • 而对于少量数据的操作,则可能需要考虑其他更轻量级的方法。

如何获取生成的主键

  • 如果使用useGeneratedKeys属性并设置其值为true,MyBatis会在插入操作后自动将生成的主键设置回实体对象的对应属性。
<insert id="insertUser" parameterType="com.example.User" useGeneratedKeys="true" keyProperty="id">  
    INSERT INTO user (name, age) VALUES (#{name}, #{age})  
</insert>
  • 执行插入操作后,可以直接从实体对象中获取主键值。
User user = new User();  
user.setName("John Doe");  
user.setAge(30);  
userMapper.insertUser(user);  
// 主键值现在已经被设置回user对象的id属性中  
long id = user.getId();  
System.out.println("Generated ID: " + id);

当实体类中的属性名和表中的字段名不一样 ,怎么办

  1. 可以使用来映射数据库表的字段到实体类的属性。
<resultMap id="UserResultMap" type="com.example.User">  
    <id property="id" column="user_id" />  
    <result property="name" column="user_name" />  
</resultMap>  
  
<select id="selectUser" resultMap="UserResultMap">  
    SELECT * FROM user  
</select>
  1. 使用别名:
    在SQL查询中,你可以使用别名来确保查询结果的列名与实体类的属性名相匹配。不过,这种方式通常需要在每个查询中手动指定,不够灵活。
SELECT user_id AS id, user_name AS name FROM user
  • 使用@Field注解(MyBatis-Plus):
    MyBatis-Plus,提供了一个@Field注解,指定数据库中的字段名。
public class User {  
    @TableId  
    @Field("user_id") // 指定数据库中的字段名为user_id  
    private Long id;  
 
    @Field("user_name") // 指定数据库中的字段名为user_name  
    private String name;  
 
    // getters and setters  
}

Mapper 编写有哪几种方式?

  1. 基于XML的Mapper编写方式:

    • 需要编写XML映射文件来定义SQL语句和结果映射。每个XML映射文件对应一个Mapper接口,其中XML文件中的namespace属性需要设置为Mapper接口的全路径。
    • 在XML文件中,你可以使用各种标签(如<select>、<insert>、<update>、<delete>等)来定义SQL语句,并通过参数类型和结果类型来指定输入和输出的数据类型。
    • 这种方式的优点是SQL语句和Java代码分离,便于管理和维护。同时,XML文件具有很好的可读性和扩展性,可以方便地添加和修改SQL语句。
  2. 基于注解的Mapper编写方式:

    • 直接在Mapper接口的方法上使用注解来定义SQL语句。例如,使用@Select注解来定义查询语句,使用@Insert注解来定义插入语句等。
    • 优点是减少了XML文件的数量,使得项目结构更加简洁。同时,注解方式更加直观,可以在Java代码中直接看到SQL语句的定义。
    • 缺点是当SQL语句较为复杂或者需要动态生成时,注解方式可能会变得不够灵活和易于管理。

MyBatis的接口绑定概念?有哪些实现方式?

MyBatis的接口绑定概念是指在MyBatis框架中,将Java接口与SQL映射文件进行关联,实现接口方法与SQL语句的对应关系。通过这种方式,程序员可以更加便捷地调用接口方法,从而执行相应的SQL操作。

  • 实现方式主要有两种:

    1. 通过XML映射文件实现接口绑定:这种方式需要提供一个与接口对应的mapper.xml文件。在XML文件中,使用标签将接口与XML文件关联,并使用、、、等标签定义相应的SQL操作。然后,在接口中声明与XML文件中定义的SQL操作相匹配的方法。MyBatis会自动根据接口和对应的XML文件创建一个接口的实现类,从而实现接口与SQL语句的绑定。
    2. 通过注解实现接口绑定:MyBatis允许在接口的方法上使用注解(如@Select、@Insert、@Update、@Delete等)来定义SQL语句。这些注解告诉MyBatis如何将接口方法与SQL语句进行绑定。使用注解的方式可以更加简洁地实现接口绑定,并且允许通过动态构建SQL语句实现更灵活的SQL操作。
  • 注意:

    • 确保XML文件名或注解中的namespace与接口的全限定名保持一致,保证MyBatis能够正确地将接口与SQL语句进行绑定
    • 接口中的方法名应与XML文件中的SQL语句id或注解中定义的SQL语句名对应,返回值类型和参数类型也应与方法的返回值参数保持一致

Mybatis能执行一对多,一对一的关联查询吗,有哪些实现方法

  • 一对多(One-to-Many)
    一对多关系通常用于表示如订单和订单项(Order-OrderItems)这样的关系。

    1. 使用和标签
      你可以在MyBatis的映射文件中使用元素来定义结果映射,并使用元素来处理一对多的关系。
    			<resultMap id="OrderResultMap" type="Order">  
    			    <id property="id" column="order_id" />  
    			    <result property="orderDate" column="order_date" />  
    			    <collection property="orderItems" ofType="OrderItem" resultMap="OrderItemResultMap" />  
    			</resultMap>  
    			  
    			<resultMap id="OrderItemResultMap" type="OrderItem">  
    			    <id property="id" column="item_id" />  
    			    <result property="productName" column="product_name" />  
    			    <!-- 其他OrderItem属性 -->  
    			</resultMap>  
    			  
    			<select id="selectOrderWithItems" resultMap="OrderResultMap">  
    			    SELECT * FROM orders o  
    			    LEFT JOIN order_items oi ON o.order_id = oi.order_id  
    			    WHERE o.order_id = #{orderId}  
    			</select>
    
    1. 使用嵌套查询(Nested Queries)
      你也可以使用嵌套查询来处理一对多关系。这涉及到两个独立的查询,一个用于获取主对象,另一个用于获取关联对象列表。
    <select id="selectOrder" resultType="Order">  
    		 SELECT * FROM orders WHERE order_id = #{orderId}  
    </select>  
    			  
    <select id="selectOrderItemsByOrderId" resultType="OrderItem">  
    	 SELECT * FROM order_items WHERE order_id = #{orderId}  
    </select>
    
  • 一对一(One-to-One)
    一对一关系通常用于表示如用户和用户详情(User-UserDetails)这样的关系。

    1. 使用和标签
      与一对多类似,你可以使用标签来处理一对一关系。

      <resultMap id="UserResultMap" type="User">  
          <id property="id" column="user_id" />  
          <result property="username" column="username" />  
          <association property="userDetails" javaType="UserDetails" resultMap="UserDetailsResultMap" />  
      </resultMap>  
        
      <resultMap id="UserDetailsResultMap" type="UserDetails">  
          <id property="id" column="details_id" />  
          <result property="email" column="email" />  
          <!-- 其他UserDetails属性 -->  
      </resultMap>  
        
      <select id="selectUserWithDetails" resultMap="UserResultMap">  
          SELECT u.*, d.* FROM users u  
          LEFT JOIN user_details d ON u.user_id = d.user_id  
          WHERE u.user_id = #{userId}  
      </select>
      
    2. 使用嵌套查询(Nested Queries)
      与一对多类似,你也可以使用嵌套查询来处理一对一关系。

      <select id="selectUser" resultType="User">  
          SELECT * FROM users WHERE user_id = #{userId}  
      </select>  
        
      <select id="selectUserDetailsByUserId" resultType="UserDetails">  
          SELECT * FROM user_details WHERE user_id = #{userId}  
      </select>
      
  • 注意事项

    • 当处理关联查询时,要注意SQL查询的性能优化,特别是当关联的数据量很大时。
      使用和/标签时,确保属性名和列名的映射是正确的。
    • 对于复杂的关联查询,可能需要使用更高级的SQL特性,如子查询、连接查询等。考虑到性能和可读性,有时候可能需要权衡是否使用关联查询,或者是否使用懒加载(Lazy Loading)等策略来延迟加载关联数据。

相关问题

使用MyBatis的mapper接口调用时有哪些要求?

  • 需要遵循以下要求和规范:

    1. 接口命名规范:Mapper接口的命名应遵循一定的规范,通常以Mapper作为后缀,如UserMapper、OrderMapper等,以便于理解该接口的用途和作用。
    2. 方法命名规范:Mapper接口中的方法名应与SQL映射文件中定义的SQL语句的id一致。同时,方法名应具备一定的语义,以便于开发者理解方法的作用。
    3. 参数传递方式:Mapper接口的方法可以接收多个参数。参数传递可以通过注解方式(@Param)直接在方法参数中使用注解来指定参数名称,或者通过Map、对象等方式传递参数。
    4. 映射SQL语句:Mapper接口中的方法并不直接包含SQL语句,而是使用注解或者XML映射文件将SQL语句与方法进行关联。这意味着你需要在XML映射文件中定义SQL语句,并通过namespace和id等属性与Mapper接口进行匹配
    5. 类型匹配:Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型应该相同,同时,Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型也应该相同。

此外,当在应用代码中不结合Spring来使用MyBatis时,你需要通过SqlSession获取mapper接口对应的代理对象(如MapperProxy),然后通过该代理对象来调用并执行mapper接口的方法。

Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?

  • 在MyBatis的XML映射文件中,不同的XML映射文件中的id不可以重复。每个id必须在其所在的命名空间中唯一

    • MyBatis通过namespace和id的组合来唯一标识一个SQL语句。namespace通常是Mapper接口的全路径名,而id则是Mapper接口中方法的名称。
      • 有两个不同的XML映射文件,
        • namespace不同,id可以相同。
        • namespace相同,id必须唯一。
  • 示例:

    • 两个Mapper接口UserMapperOrderMapper,都有一个名为findById的方法,可以在UserMapper.xml中定义一个id为findById的SQL语句,同时在OrderMapper.xml中也定义一个id为findById的SQL语句
      • 如果它们的namespace分别是UserMapperOrderMapper的全路径,不会产生冲突。

      • 但是,如果在UserMapper.xml中定义两个或更多id为findById的SQL语句,将无法区分它们,从而导致运行时错误。

Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系?

  1. XML 映射文件的基本结构,包含以下元素

    • <mapper>:根元素,用于定义命名空间(namespace),通常与对应的 Mapper 接口的全限定名一致。
    • <select>、<insert>、<update>、<delete>:用于定义 SQL 语句,分别对应查询、插入、更新和删除操作。
    • <resultMap>:用于定义结果集映射关系,包括如何将数据库字段映射到 Java 对象的属性。
    • <parameterType> 和 <resultType>:用于指定 SQL 语句的参数类型返回类型
  2. 内部数据结构

    • Configuration:MyBatis 的核心配置类,包含了所有的配置信息,如环境信息、别名、类型处理器、映射器等。
    • MapperStatement:代表一个映射语句,包含了 SQL 语句、参数类型、返回类型等信息。
    • ResultMap:表示结果集的映射关系,用于将查询结果映射到 Java 对象。
    • ParameterHandler:处理 SQL 语句的参数
    • ResultSetHandler:处理 SQL 语句的结果集
  3. 映射关系

    • 命名空间与 Mapper 接口:XML 映射文件的 元素定义的命名空间通常与对应的 Mapper 接口的全限定名一致。这样,MyBatis 就可以通过命名空间找到对应的 Mapper 接口,进而找到对应的 SQL 语句。
    • SQL 语句与 MapperStatement:XML 映射文件中的 <select>、<insert>、<update>、<delete> 元素定义的 SQL 语句会被解析为 MapperStatement 对象,存储在 Configuration 中。这些 MapperStatement 对象包含了 SQL 语句、参数类型、返回类型等信息。
    • 结果集映射与 ResultMap:XML 映射文件中的 元素定义的结果集映射关系会被解析为 ResultMap 对象,同样存储在 Configuration 中。当执行查询操作时,MyBatis 会使用 ResultMap 将查询结果映射到 Java 对象。
    • 参数类型与 ParameterHandler:XML 映射文件中通过 或注解指定的参数类型会被用于创建 ParameterHandler 对象,该对象负责处理 SQL 语句的参数。
    • 返回类型与 ResultSetHandler:XML 映射文件中通过 或 指定的返回类型会被用于创建 ResultSetHandler 对象,该对象负责处理查询结果集,并将其映射到 Java 对象。
  4. 总结

    MyBatis 通过 XML 映射文件定义了 SQL 语句与 Java 对象之间的映射关系,并将这些映射关系解析为内部数据结构(如MapperStatement、ResultMap 等)进行存储和处理。当执行数据库操作时,MyBatis 会根据这些内部数据结构生成相应的 SQL 语句,并处理参数和结果集,从而实现数据的持久化操作。

Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?

1、封装为目标对象并返回

  • 过程主要涉及到SQL映射文件、ResultMap以及SQL执行。

    • SQL映射文件

      • 通常是XML格式,包含了要执行的SQL语句以及与这些语句关联的Java对象。
      • SQL语句通过<select>、<insert>、<update>或<delete>等元素进行定义。
    • ResultMap

      • ResultMap定义了如何从查询结果提取数据,并将其映射到Java对象的属性上。
      • 当查询结果返回时,MyBatis会自动根据ResultMap的定义,将结果映射到正确的Java类中。
    • SQL执行

      • 执行前:需要先创建SqlSession并将其绑定到适当的DataSource(连接数据库的连接池工厂)。
      • 执行中:可以使用MyBatis的API来执行SQL语句。
      • 执行后:根据映射文件中定义的ResultMap,将SQL执行结果封装为目标对象并返回。

2、映射形式

  • 使用resultType属性:你可以将查询结果的列直接映射到Java对象的属性上。例如,在XML映射文件中,这样定义查询:MyBatis会自动将查询结果的每一列映射到User对象的对应属性上。

    <select id="selectUser" resultType="com.example.User">SELECT * FROM user WHERE id=#{id}</select>
    
  • 使用resultMap属性:这种方式提供了更灵活的映射方式。可以通过<resultMap>标签,逐一定义列名和对象属性名之间的映射关系。这样,可以更精确地控制如何将数据库字段映射到Java对象的属性上。

  • 使用SQL列的别名功能:通过在SQL查询中使用列的别名,并将别名设置为Java对象的属性名,来实现映射。MyBatis会智能地找到与别名对应的Java对象属性名,并完成映射。

Mybatis映射文件中,如果A标签通过include引用了B标签的内容,AB标签之间的定义顺序是否受到影响?

  • MyBatis 在解析映射文件时,会先解析整个文件,并构建内部的映射结构。因此,不论被引用的 SQL 片段在文件中的位置如何,MyBatis 都能正确地找到并引用它。

  • 举例子(尽管 SQL 片段 B 定义在引用它的 A 标签之前,但 MyBatis 仍然能够正确地解析并执行这个查询。)

    <mapper namespace="com.example.MyMapper">  
      
        <!-- 定义被引用的 SQL 片段 B -->  
        <sql id="B">  
            column1, column2  
        </sql>  
      
        <!-- 定义引用 SQL 片段 B 的 A 标签 -->  
        <select id="selectExample" resultType="com.example.Example">  
            SELECT  
            <include refid="B" />  
            FROM some_table  
            WHERE some_condition  
        </select>  
      
    </mapper>
    
  • 同样地,也可以将 SQL 片段 B 放在 A 标签的后面,MyBatis 依然能够正常工作:

    <mapper namespace="com.example.MyMapper">  
      
        <!-- 定义引用 SQL 片段 B 的 A 标签 -->  
        <select id="selectExample" resultType="com.example.Example">  
            SELECT  
            <include refid="B" />  
            FROM some_table  
            WHERE some_condition  
        </select>  
      
        <!-- 定义被引用的 SQL 片段 B -->  
        <sql id="B">  
            column1, column2  
        </sql>  
      
    </mapper>
    

在这种情况下,由于 MyBatis 在解析时会先构建整个映射结构,所以 SQL 片段 B 仍然可以被 A
标签正确引用。因此,可以根据代码的组织和可读性需求,自由地在映射文件中安排 SQL 片段的置。

Mybatis是否支持映射Enum枚举类

  • 可以使用TypeHandler接口来定义如何将Java枚举类型数据库中的值进行转换处理Java枚举类型与数据库中的值之间的映射

  • MyBatis默认使用EnumTypeHandler将枚举值转换为其名称进行存储,即当枚举类型的字段被持久化到数据库时,它会被保存枚举名称

    • 如果要自定义枚举类型的处理方式,比如按照枚举的序号(ordinal)或者自定义的属性来存储和读取,你可以编写自定义的TypeHandler来实现这些功能。
    • MyBatis也提供了内置的EnumOrdinalTypeHandler,该处理器会将枚举的序号(从0开始的索引)与数据库中的数字字段进行映射。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐 昊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值