MyBatis面试专题

时间:2024-03-26 08:18:08

文章目录

  • 什么是 MyBatis?
  • 讲下 MyBatis 的缓存
      • 一级缓存
      • 二级缓存
  • Mybatis 是如何进行分页的?分页插件的原理是什么?
    • 分页插件的原理
    • 举例说明
  • 简述 Mybatis 的插件运行原理,以及如何编写一个插件?
    • 插件运行原理
    • 编写一个插件的基本步骤
  • Mybatis 动态 sql 是做什么的?都有哪些动态 sql?能简述一下动态 sql 的执行原理不?
    • 动态 SQL 的执行原理
  • #{}和${}的区别是什么?
  • 为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?
    • MyBatis 的特点:
    • 全自动 ORM 映射工具的特点(如 Hibernate):
    • 区别总结:
  • Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?
  • MyBatis 与 Hibernate 有哪些不同?
  • MyBatis 的好处是什么?
  • 简述 Mybatis 的 Xml 映射文件和 Mybatis 内部数据结构之间的映射关系?
  • 什么是 MyBatis 的接口绑定,有什么好处?
  • 接口绑定有几种实现方式,分别是怎么实现的?
  • 什么情况下用注解绑定,什么情况下用 xml 绑定?
  • MyBatis 实现一对一有几种方式?具体怎么操作的?
  • Mybatis 能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别?
  • MyBatis 里面的动态 Sql 是怎么设定的?用什么语法?
  • Mybatis 是如何将 sql 执行结果封装为目标对象并返回的?都有哪些映射形式?
  • Xml 映射文件中,除了常见的 select|insert|updae|delete 标签之外,还有哪些标签?
  • 当实体类中的属性名和表中的字段名不一样,如果将查询的结果封装到指定 pojo?
  • 模糊查询 like 语句该怎么写
  • 通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应, Dao 的工作原理,是否可以重载?
  • Mybatis 映射文件中,如果 A 标签通过 include 引用了 B 标签的内容,请问,B 标签能否定义在 A 标签的后面,还是说必须定义在 A 标签的前面?
  • Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件,id 是否可以重复?
  • Mybatis 中如何执行批处理?
  • Mybatis 都有哪些 Executor 执行器?它们之间的区别是什么?
  • Mybatis 中如何指定使用哪一种 Executor 执行器?
  • Mybatis 执行批量插入,能返回数据库主键列表吗?
  • Mybatis 是否可以映射 Enum 枚举类?
  • 如何获取自动生成的(主)键值?
  • 在 mapper 中如何传递多个参数?
  • resultType resultMap 的区别?
  • 使用 MyBatis 的 mapper 接口调用时有哪些要求?
  • Mybatis 比 IBatis 比较大的几个改进是什么?
  • IBatis 和 MyBatis 在核心处理类分别叫什么?
  • IBatis 和 MyBatis 在细节上的不同有哪些?


什么是 MyBatis?

MyBatis 是一个持久层框架,它主要用于简化数据库操作,并提供了灵活的 SQL 编写和结果映射功能。其主要特点包括:

  1. SQL 映射配置文件:MyBatis 使用 XML 文件或注解来配置 SQL 语句,从而将 SQL 语句与 Java 方法进行映射。

  2. 灵活的 SQL 编写:MyBatis 允许开发人员编写自定义的 SQL 语句,可以直接在 XML 文件中编写 SQL,也可以使用注解方式在 Java 代码中编写。

  3. 参数映射:MyBatis 支持将 Java 对象作为参数传递给 SQL 语句,并可以自动映射参数到 SQL 语句中。

  4. 结果映射:MyBatis 提供了灵活的结果映射功能,可以将 SQL 查询结果映射到 Java 对象中,支持一对一、一对多等复杂关系的映射。

  5. 事务支持:MyBatis 提供了对事务的支持,可以使用声明式或编程式事务管理来管理数据库操作。

  6. 缓存机制:MyBatis 提供了一级缓存和二级缓存的支持,可以提高数据库访问性能。

  7. 与 Spring 集成:MyBatis 可以与 Spring 框架无缝集成,可以通过 Spring 提供的事务管理和依赖注入功能来管理 MyBatis 的 SQL 会话和映射器。

总的来说,MyBatis 是一个功能强大且灵活的持久层框架,它提供了丰富的功能和灵活的配置选项,可以帮助开发人员简化数据库操作,并提高系统的性能和可维护性。

讲下 MyBatis 的缓存

MyBatis 提供了一级缓存和二级缓存来提高数据库查询性能和减少数据库交互次数。下面分别介绍一下这两种缓存的特点和使用方法:

一级缓存

一级缓存是指在同一个 SQLSession 内部的缓存。默认情况下,每个 SQLSession 对象都拥有自己的一级缓存,且一级缓存是开启的。一级缓存的特点如下:

  • 生命周期:一级缓存的生命周期与 SQLSession 相同,即在同一个 SQLSession 中执行的多次查询可以共享一级缓存。
  • 作用范围:一级缓存仅限于同一个 SQLSession 中,不同的 SQLSession 之间的缓存是相互独立的。
  • 自动刷新:一级缓存是自动刷新的,当执行了增删改操作时,会自动清空对应的一级缓存。

二级缓存

二级缓存是指多个 SQLSession 共享的缓存,可以跨越多个 SQLSession,多个 Mapper 接口之间可以共享二级缓存。但是需要注意,二级缓存是需要手动开启的,且默认情况下是关闭的。二级缓存的特点如下:

  • 生命周期:二级缓存的生命周期与整个应用程序相同,即多个 SQLSession 之间可以共享二级缓存。
  • 作用范围:二级缓存是全局的,多个 SQLSession 之间可以共享二级缓存。
  • 配置:需要在映射文件中进行配置,使用 <cache/> 标签来启用和配置二级缓存。
<!-- 在映射文件中配置二级缓存 -->
<mapper namespace="com.example.mapper.UserMapper">
    <cache/>
</mapper>
  • 序列化要求:为了支持跨 SQLSession 序列化和反序列化对象,缓存的对象需要实现 Serializable 接口。

使用缓存时需要注意以下几点:

  • 对于频繁更新的数据,不建议使用缓存,因为会导致缓存频繁失效,反而增加了数据库的负担。
  • 对于不经常更新的数据,可以适当使用缓存来提高查询性能,但需要注意缓存的命中率和缓存的更新策略。
  • 在需要的时候可以手动清除缓存,可以通过调用 sqlSession.clearCache() 方法来清空一级缓存,或者通过 <cache-ref namespace="otherNamespace"/> 来引用其他命名空间的缓存。

综上所述,MyBatis 的缓存功能可以有效地提高数据库查询性能,但需要根据实际情况进行合理配置和使用。

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

MyBatis 实现分页的方式有多种,包括使用 RowBounds 对象、直接编写 SQL 实现分页以及使用 MyBatis 的分页插件。下面我将详细介绍 MyBatis 分页插件的原理和实现方式:

分页插件的原理

MyBatis 分页插件的原理是通过自定义拦截器(Interceptor)来拦截待执行的 SQL,并在拦截器中重写 SQL 实现分页功能。具体步骤如下:

  1. 实现自定义插件(Interceptor):首先,需要编写一个实现了 MyBatis 的 Interceptor 接口的自定义插件,该插件用于拦截 SQL 执行过程中的方法。

  2. 拦截待执行的 SQL:在自定义插件中,通过重写 MyBatis 的 Executor 对象的 query 方法,拦截待执行的 SQL 语句。

  3. 解析原始 SQL:在拦截到待执行的 SQL 后,需要对原始 SQL 进行解析,获取其中的表名、字段等信息,以便后续的分页处理。

  4. 重写 SQL:在解析完原始 SQL 后,根据数据库类型(如 MySQL、Oracle 等)以及分页参数(如页码、每页数量)等信息,构造相应的分页 SQL。

  5. 执行重写后的 SQL:最后,使用重写后的 SQL 来执行数据库查询,并返回查询结果,实现分页功能。

举例说明

假设原始 SQL 为 SELECT * FROM student,我们希望实现查询结果的分页显示,每页显示 10 条数据,第一页从第 0 条开始。下面是一个简单的分页插件的示例:

public class PaginationInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 拦截待执行的 SQL
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameter = args[1];
        RowBounds rowBounds = (RowBounds) args[2];
        
        // 解析原始 SQL
        BoundSql boundSql = ms.getBoundSql(parameter);
        String originalSql = boundSql.getSql();
        
        // 构造分页 SQL
        String pageSql = buildPageSql(originalSql, rowBounds);
        
        // 重写 SQL
        MetaObject metaStatementHandler = SystemMetaObject.forObject(invocation.getTarget());
        metaStatementHandler.setValue("delegate.boundSql.sql", pageSql);
        
        // 执行重写后的 SQL
        return invocation.proceed();
    }

    private String buildPageSql(String originalSql, RowBounds rowBounds) {
        // 构造分页 SQL,这里以 MySQL 为例
        StringBuilder pageSql = new StringBuilder(originalSql);
        pageSql.append(" LIMIT ")
               .append(rowBounds.getOffset())
               .append(",")
               .append(rowBounds.getLimit());
        return pageSql.toString();
    }
}

在上面的示例中,我们实现了一个简单的分页插件 PaginationInterceptor,通过重写拦截器的 intercept 方法,在其中拦截待执行的 SQL,并根据 RowBounds 对象中的分页信息构造分页 SQL,最后通过反射将重写后的 SQL 设置到原始的 BoundSql 中。这样就实现了 MyBatis 的分页功能。

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

你提到的是 MyBatis 的插件功能,下面我将简要介绍 MyBatis 插件的运行原理以及编写一个插件的基本步骤:

插件运行原理

MyBatis 插件的运行原理基于动态代理。当 MyBatis 执行需要拦截的接口方法时,会通过动态代理生成一个代理对象,并在代理对象的方法中调用插件的拦截方法。具体步骤如下:

  1. MyBatis 会为需要拦截的接口生成代理对象。
  2. 当调用代理对象的方法时,实际上会调用插件的拦截方法。
  3. 在插件的拦截方法中,可以对方法的参数和返回值进行处理,实现自定义的功能。
  4. 最终,插件可以选择继续执行原始方法,也可以选择终止执行。

编写一个插件的基本步骤

下面是编写一个 MyBatis 插件的基本步骤:

  1. 创建一个类,实现 MyBatis 的 Interceptor 接口。
  2. 在实现的 Interceptor 接口中实现 intercept() 方法,这是插件的核心方法,用于拦截需要处理的接口方法。
  3. 在 intercept() 方法中编写插件的具体逻辑,可以对方法的参数和返回值进行处理,实现自定义的功能。
  4. 使用 @Intercepts 注解指定需要拦截的接口方法,可以指定多个接口方法。
  5. 将插件注册到 MyBatis 的配置文件中,使其生效。

下面是一个简单的示例:

@Intercepts({
    @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MyPlugin implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 拦截 Executor 的 update 方法
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameter = args[1];
        
        // 在此处编写插件的具体逻辑
        
        // 调用原始方法
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        // 生成代理对象
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 设置插件属性
    }
}

在上面的示例中,我们创建了一个名为 MyPlugin 的插件,通过 @Intercepts 注解指定需要拦截的方法为 Executor 接口的 update 方法。在 intercept() 方法中,我们可以编写插件的具体逻辑,对方法的参数和返回值进行处理。最后,通过 Plugin.wrap() 方法生成代理对象,使插件生效。

在 MyBatis 的配置文件中,需要将插件注册为插件列表的一部分,以便插件生效。例如:

<plugins>
    <plugin interceptor="com.example.MyPlugin">
        <!-- 可以配置插件的属性 -->
    </plugin>
</plugins>

以上就是编写一个 MyBatis 插件的基本步骤。

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

动态 SQL 的执行原理

  1. 解析和组装: MyBatis 在解析 XML 映射文件时,会识别并解析动态 SQL 标签,例如 <if>, <choose>, <foreach> 等。
  2. 条件判断: 对于带有条件判断的标签,如 <if>,MyBatis 会通过 OGNL 表达式计算条件的值,根据条件的结果来决定是否执行标签内的 SQL 语句。
  3. 循环处理: 对于循环标签,如 <foreach>,MyBatis 会遍历集合并根据集合的元素动态生成对应的 SQL 片段。
  4. SQL 组装: MyBatis 将经过条件判断和循环处理后的 SQL 片段进行组装,形成完整的 SQL 语句。
  5. 参数绑定: MyBatis 将参数绑定到 SQL 语句中,确保参数的值正确传递到 SQL 语句中的占位符处。
  6. SQL 执行: 最后,MyBatis 将完整的 SQL 语句发送给数据库执行,从而完成动态 SQL 的执行过程。

总的来说,MyBatis 的动态 SQL 执行原理就是根据 XML 映射文件中的动态 SQL 标签,结合参数对象的属性值,动态生成 SQL 语句,并将参数值绑定到 SQL 中,最终执行生成的 SQL 语句。

#{}和${}的区别是什么?

  1. 预编译处理 vs. 字符串替换:

    • #{} 是 MyBatis 的参数占位符,它会被解析为一个问号 ?,并由 JDBC 预编译处理。这意味着参数值会作为参数传递给 SQL 语句,可以有效防止 SQL 注入攻击。
    • ${} 则是简单的字符串替换,它会被直接替换为参数的值,不会被预编译处理。这样的话,如果不谨慎处理用户输入,可能会导致 SQL 注入攻击。
  2. 安全性:

    • 由于 #{} 是预编译处理,因此具有更高的安全性,能够有效防止 SQL 注入攻击。
    • ${} 则较为脆弱,如果直接将用户输入的值放在 ${} 中,可能会导致 SQL 注入问题。
  3. 参数传递方式:

    • #{} 是通过参数绑定的方式,MyBatis 会将参数值以安全的方式传递给 SQL 语句,适用于大多数场景。
    • ${} 则是简单的字符串替换,适用于一些特殊情况,如动态拼接 SQL。
  4. 语法结构:

    • #{} 在 SQL 中使用,表示参数占位符,例如 WHERE id = #{userId}
    • ${} 则是字符串替换,将其内部的内容替换为实际的值,例如 WHERE id = ${userId}

为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?

MyBatis 的特点:

  1. 半自动化: MyBatis 是一种半自动的 ORM(对象关系映射)工具,它需要手动编写 SQL 查询语句来完成对象与关系数据库之间的映射。这意味着开发人员需要显式地定义 SQL 查询,并且需要处理结果集的映射。

  2. 灵活性: MyBatis 提供了灵活性,开发人员可以直接编写 SQL,从而更好地控制 SQL 的执行过程。这使得开发人员可以根据实际需求进行优化和调整,以获得更好的性能和更精确的结果。

  3. SQL 控制权: 开发人员可以直接控制 SQL 的编写和执行过程,包括优化、调整和定制 SQL 查询。这样可以更好地理解和掌握底层数据库操作,适用于一些复杂的业务场景。

全自动 ORM 映射工具的特点(如 Hibernate):

  1. 全自动化: 全自动 ORM 工具(如 Hibernate)通过对象关系映射来实现,开发人员无需编写 SQL 查询语句,而是通过对象之间的关系来查询和操作数据库。这使得开发过程更加简单和高效。

  2. 透明性: 全自动 ORM 工具隐藏了底层数据库操作细节,开发人员不需要关心数据库的具体实现细节,只需关注业务对象和关系之间的映射关系。

  3. 学习曲线低: 由于全自动 ORM 工具抽象了底层数据库操作,因此开发人员可以更快地上手,并且无需深入了解 SQL 查询语句的编写和优化。

区别总结:

  • MyBatis 是一种半自动 ORM 映射工具,需要开发人员手动编写 SQL 查询语句,具有灵活性和可控性。
  • 全自动 ORM 映射工具(如 Hibernate)则隐藏了底层数据库操作细节,提供了更简单、更便捷的开发方式,但可能会牺牲一些灵活性和可控性。

Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?

  1. 支持延迟加载

    • Mybatis仅支持关联对象(association)和关联集合对象(collection)的延迟加载。关联对象指的是一对一关系,关联集合指的是一对多查询。
    • 在Mybatis配置文件中,可以设置是否启用延迟加载,即lazyLoadingEnabled=true|false
  2. 实现原理

    • Mybatis通过使用CGLIB创建目标对象的代理对象来实现延迟加载。
    • 当调用目标方法时,进入拦截器方法。例如,调用a.getB().getName(),拦截器的invoke()方法检测到a.getB()为null值,就会单独发送预先保存的查询关联B对象的SQL。
    • 查询到B对象后,调用a.setB(b)来为对象a的属性b赋值。
    • 然后完成a.getB().getName()方法的调用。

MyBatis 与 Hibernate 有哪些不同?

  1. ORM框架差异

    • MyBatis并非完全的ORM框架,需要程序员自行编写SQL语句,但可以通过XML或注解方式配置SQL语句和Java对象的映射。
    • Hibernate是典型的ORM框架,负责对象/关系映射,程序员无需编写SQL语句,通过对象来操作数据库。
  2. 学习门槛和灵活性

    • MyBatis学习门槛低,简单易学,灵活度高,适用于对关系数据模型要求不高的软件开发,如互联网软件、企业运营类软件。
    • Hibernate学习门槛高,需要精通,但能提高开发效率,对于关系模型要求高的定制化软件开发更为适用。
  3. 数据库无关性

    • MyBatis缺乏数据库无关性,需要自定义多套SQL映射文件来支持多种数据库。
    • Hibernate具有良好的数据库无关性,能够更好地适应不同数据库环境。
  4. 性能和灵活性权衡

    • MyBatis可以严格控制SQL执行性能,但无法做到数据库无关性,需要权衡性能和灵活性。
    • Hibernate对于关系模型要求高的软件能够提高开发效率,但在性能和对象模型之间的权衡上需要有经验和能力。

总之,根据软件需求在有限资源环境下选择适合的框架最为重要,维护性、扩展性良好的软件架构才是最优选择。

MyBatis 的好处是什么?

  1. SQL与Java代码分离

    • MyBatis将SQL语句与Java代码分离,单独存放在XML文件中,提高了程序的可维护性和可读性。
  2. 封装底层JDBC细节

    • MyBatis封装了底层JDBC API的调用细节,使得数据库操作更加简单,程序员无需处理繁琐的JDBC操作,同时能够自动将结果集转换成Java Bean对象。
  3. 灵活控制SQL语句

    • MyBatis需要程序员自行编写SQL语句,这使得程序员可以根据数据库特点灵活控制SQL语句的编写,从而实现更高效的查询和更复杂的操作。
    • 相比于全自动的ORM框架如Hibernate,MyBatis更容易实现高效的查询,能够满足复杂查询的需求。

总的来说,MyBatis通过SQL与Java代码分离、封装底层JDBC细节以及灵活控制SQL语句等特点,提供了更加灵活、可维护和高效的数据库操作方式。

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

在MyBatis中,XML映射文件中的各种标签会被解析成MyBatis内部的数据结构,主要映射关系如下:

  1. <parameterMap>标签:

    • 被解析为ParameterMap对象。
    • <parameterMap>的子元素会被解析为ParameterMapping对象。
  2. <resultMap>标签:

    • 被解析为ResultMap对象。
    • <resultMap>的子元素会被解析为ResultMapping对象。
  3. <select><insert><update><delete>标签:

    • 每一个都会被解析为MappedStatement对象。
    • 标签内的SQL会被解析为BoundSql对象。

这些MyBatis内部数据结构,如ParameterMapParameterMappingResultMapResultMappingMappedStatementBoundSql等,都是在MyBatis运行时用来表示XML配置信息和执行SQL的重要对象。通过这种映射关系,MyBatis能够将XML配置文件中的各种配置信息转换成程序中能够操作的对象,从而实现SQL的动态执行和结果映射。

什么是 MyBatis 的接口绑定,有什么好处?

MyBatis的接口绑定是指在MyBatis中定义接口,并将接口方法与对应的SQL语句进行绑定。通过这种方式,可以直接调用接口方法来执行SQL操作。

接口绑定的好处包括:

  1. 简化代码:通过接口绑定,可以将SQL语句与Java接口方法直接对应,避免了手动编写SQL语句的繁琐过程,使代码更加简洁清晰。

  2. 类型安全:由于接口方法的签名与SQL语句的执行方式一一对应,因此可以在编译时进行类型检查,避免了在运行时出现SQL语法错误等问题。

  3. 提高可维护性:接口绑定将SQL语句与Java代码解耦,使得修改SQL语句或者调整SQL执行逻辑变得更加方便,提高了代码的可维护性。

  4. 灵活性:通过接口绑定,可以在不修改Java代码的情况下修改SQL语句,从而实现灵活的SQL调整和优化,提高了系统的灵活性和可扩展性。

总之,MyBatis的接口绑定机制可以使得代码更加简洁、可读性更高、类型安全,并且提高了系统的灵活性和可维护性,是MyBatis框架的重要特性之一。

接口绑定有几种实现方式,分别是怎么实现的?

接口绑定在MyBatis中有两种主要的实现方式:

  1. 注解绑定

    • 通过在接口的方法上添加注解(如@Select、@Update等),并在注解中包含对应的SQL语句来实现绑定。
    • 示例:
      public interface UserMapper {
          @Select("SELECT * FROM users WHERE id = #{id}")
          User getUserById(int id);
          
          @Update("UPDATE users SET name = #{name} WHERE id = #{id}")
          int updateUserName(@Param("id") int id, @Param("name") String name);
      }
      
    • 在这种方式下,MyBatis会根据注解中的SQL语句执行对应的操作。
  2. XML配置绑定

    • 通过在XML映射文件中编写SQL语句,并将接口的方法与XML文件中的SQL语句进行绑定。
    • 在XML映射文件中,需要指定namespace为接口的全路径名,然后在文件中定义与接口方法对应的SQL语句。
    • 示例:
      <!-- UserMapper.xml -->
      <mapper namespace="com.example.mapper.UserMapper">
          <select id="getUserById" resultType="User">
              SELECT * FROM users WHERE id = #{id}
          </select>
          
          <update id="updateUserName" parameterType="User">
              UPDATE users SET name = #{name} WHERE id = #{id}
          </update>
      </mapper>
      
    • 在这种方式下,MyBatis会根据接口方法的名称和XML映射文件中的SQL语句执行对应的操作。

总的来说,无论是通过注解绑定还是XML配置绑定,都可以实现接口方法与SQL语句的绑定,提供了不同的灵活性和选择性来满足不同的需求。

什么情况下用注解绑定,什么情况下用 xml 绑定?

使用注解绑定和XML绑定的选择取决于SQL语句的复杂度和个人偏好,一般来说:

注解绑定适用情况

  • 当SQL语句比较简单,例如单表的简单查询、插入、更新等操作时,可以使用注解绑定。
  • 当希望将SQL语句直接与接口方法绑定在一起,以提高代码的可读性和简洁性时,可以选择注解绑定。
  • 当项目中只有少量的SQL操作,并且希望减少XML配置文件的数量时,注解绑定也是一个不错的选择。

XML绑定适用情况

  • 当SQL语句较为复杂,涉及到多表关联查询、动态SQL、复杂的条件判断等情况时,使用XML绑定更为合适。
  • 当希望将SQL语句与Java代码分离,以提高代码的可维护性和灵活性时,应该选择XML绑定。
  • 当项目中包含大量的SQL操作,或者希望通过namespace进行更好的组织和管理时,XML绑定通常更适合。

综合来说,简单的SQL操作和个别的查询可以选择注解绑定,而复杂的SQL操作和大型项目则更适合使用XML绑定。同时,注解绑定和XML绑定也可以混合使用,根据具体情况选择最合适的方式。

MyBatis 实现一对一有几种方式?具体怎么操作的?

在MyBatis中实现一对一关联查询有两种主要的方式:联合查询和嵌套查询。

1. 联合查询

  • 联合查询是指在SQL语句中通过多个表的联合查询来获取一对一关联的数据。
  • 配置步骤:
    1. 在SQL语句中编写联合查询,将多个表关联起来,并通过查询条件确保一对一关联的数据。
    2. 在MyBatis的映射文件中,使用<resultMap>配置一对一关联关系,使用<association>标签配置关联的对象。

示例

<!-- SQL语句 -->
SELECT * FROM user u
JOIN user_profile up ON u.id = up.user_id
WHERE u.id = #{userId}

<!-- MyBatis映射文件 -->
<resultMap id="UserResultMap" type="User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <association property="profile" javaType="UserProfile">
        <id property="id" column="profile_id"/>
        <result property="fullName" column="full_name"/>
        <result property="email" column="email"/>
    </association>
</resultMap>

2. 嵌套查询

  • 嵌套查询是指先查询主表,然后根据主表的结果中的外键ID去关联的表中进行查询,获取一对一关联的数据。
  • 配置步骤:
    1. 在MyBatis的映射文件中,使用<resultMap>配置一对一关联关系,使用<association>标签配置关联的对象,并通过select属性指定嵌套查询的SQL语句。

示例

<!-- MyBatis映射文件 -->
<resultMap id="UserResultMap" type="User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <association property="profile" javaType="UserProfile" select="selectProfileByUserId"/>
</resultMap>

<!-- 嵌套查询的SQL语句 -->
<select id="selectProfileByUserId" resultType="UserProfile">
    SELECT * FROM user_profile WHERE user_id = #{userId}
</select>

综上所述,MyBatis实现一对一关联查询可以通过联合查询或者嵌套查询两种方式来实现,根据实际情况选择合适的方式。

Mybatis 能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别?

MyBatis可以执行一对一、一对多、多对一、多对多的关联查询,它们的实现方式和区别如下:

  1. 一对一关联查询

    • 实现方式
      • 单独发送一个SQL去查询关联对象,然后将关联对象赋给主对象,最后返回主对象。
      • 使用嵌套查询(JOIN查询),将主对象和关联对象在同一个SQL查询中获取。
    • 区别
      • 单独查询方式需要发送两个SQL查询,一次查询主对象,一次查询关联对象,然后手动关联它们。
      • 嵌套查询方式只发送一个SQL查询,主对象和关联对象在同一个查询结果集中,更为高效。
  2. 一对多关联查询

    • 实现方式
      • 在主对象的映射文件中通过<collection>标签配置一对多关联关系,然后在查询主对象时,MyBatis会自动执行关联查询获取对应的多个关联对象。
    • 区别
      • MyBatis会根据一对多关系的配置自动执行关联查询,无需手动操作,简化了开发流程。
  3. 多对一关联查询

    • 实现方式
      • 多对一查询实际上就是一对一查询,只需要修改查询方法,例如将selectOne()修改为selectList()即可。
    • 区别
      • 在数据库层面,多对一关联查询是通过外键来建立关联的,但在MyBatis中查询方式和一对一查询相同。
  4. 多对多关联查询

    • 实现方式
      • 多对多查询实际上就是一对多查询,只需要修改查询方法,例如将selectOne()修改为selectList()即可。
    • 区别
      • 多对多关联查询在数据库层面通常会通过中间表来建立关联,但在MyBatis中查询方式和一对多查询相同。

总的来说,MyBatis可以通过不同的映射配置来实现一对一、一对多、多对一、多对多的关联查询,开发者可以根据实际需求和性能考量选择合适的实现方式。

MyBatis 里面的动态 Sql 是怎么设定的?用什么语法?

在MyBatis中,动态SQL通常是通过<if>节点实现的,同时也可以配合其他节点来控制SQL语句的动态拼接,常见的有<where><trim>节点。这些节点的语法可以使用OGNL(Object Graph Navigation Language)表达式来进行条件判断。

以下是常见的动态SQL语法及其用法:

  1. <if>节点:用于根据条件判断是否包含某部分SQL语句。
<select id="getUserByName" parameterType="string" resultType="User">
    SELECT * FROM user
    <where>
        <if test="name != null and name != ''">
            AND name = #{name}
        </if>
    </where>
</select>
  1. <where>节点:用于判断是否插入WHERE关键字,并自动去除不必要的ANDOR
<select id="getUserByCriteria" parameterType="map" resultType="User">
    SELECT * FROM user
    <where>
        <if test="name != null and name != ''">
            AND name = #{name}
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
    </where>
</select>
  1. <trim>节点:用于修剪SQL语句开头或结尾的多余字符,如ANDOR
<select id="getUserByCriteria" parameterType="map" resultType="User">
    SELECT * FROM user
    <trim prefix="WHERE" prefixOverrides="AND |OR ">