每日三个JAVA经典面试题(二十七)

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

在MyBatis中,可以通过在MyBatis的全局配置文件(mybatis-config.xml)中配置executorType属性来指定使用哪种Executor执行器。具体做法是在settings元素下设置executorType属性,例如:

xml 复制代码
<configuration>
  <settings>
    <!-- 指定执行器类型 -->
    <setting name="executorType" value="REUSE"/>
    
    <!-- 可选值:SIMPLE(默认), REUSE, BATCH -->
  </settings>

  <!-- 其他配置项... -->

</configuration>

这里,可选的executorType值包括:

  • SIMPLE: 简单执行器,默认选项,每次执行都会创建一个新的PreparedStatement。
  • REUSE: 可重用执行器,尝试重用预编译的PreparedStatement,但需要注意的是,MyBatis 3.x之后已经废弃了这个执行器。
  • BATCH: 批处理执行器,用于批量执行SQL,可以大幅提高批量插入、更新和删除操作的性能。

如果你想要在某个特定的Mapper接口或者方法级别上覆盖全局配置,可以通过在对应的mapper映射文件中的<select>, <insert>, <update>, <delete>标签上设置executorType属性来实现局部覆盖。不过要注意的是,mapper级别的executorType设置并不支持REUSE,只支持SIMPLEBATCH

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

是的,MyBatis 支持延迟加载(也称为懒加载)。延迟加载是一种优化技术,它允许在实际需要数据时才进行查询,而不是在创建对象时就加载所有可能用到的数据。这种方式可以显著提高应用程序的性能,尤其是在处理具有复杂关联关系的数据模型时。

延迟加载的配置

在 MyBatis 中启用延迟加载,需要在配置文件 mybatis-config.xml 中进行设置:

xml 复制代码
<settings>
    <!-- 开启延迟加载的总开关 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 将积极加载改为按需加载(即对象被调用时才加载) -->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>
  • lazyLoadingEnabled: 控制是否启用延迟加载,默认为 false。设置为 true 后,MyBatis 会延迟加载所有关联对象。
  • aggressiveLazyLoading: 控制加载行为,默认为 true。当设置为 false 时,对象只有在访问其关联的对象时才加载它们,而不是在加载任何属性时就加载所有关联对象。

实现原理

MyBatis 实现延迟加载的原理主要依赖于代理对象。当配置了延迟加载时,MyBatis 会为那些配置了延迟加载的关联对象创建一个代理(Proxy)。这个代理对象在外部代码首次访问它的方法时,才会触发真正的数据库查询操作。

  1. 代理对象:MyBatis 使用 CGLIB 或 JDK 动态代理(取决于对象类型是接口还是类)来创建关联对象的代理。
  2. 触发加载:当程序访问代理对象的任何方法时,代理逻辑会判断该关联对象是否已经被加载。如果还没有加载,代理就会执行实际的 SQL 查询来加载数据,并将结果设置到代理对象中。
  3. 透明访问:一旦数据被加载,代理对象就会把对它的方法调用委托给实际加载的数据对象,之后的访问就如同直接使用数据对象一样,对使用者来说是透明的。

这种延迟加载的策略允许减少初始化对象时的数据库访问量,特别是对于那些不一定需要立即使用所有数据的场景,可以有效减少资源的消耗,提高应用性能。然而,使用延迟加载时也需要注意,它可能导致 N+1 查询问题,即访问每个对象的关联数据时都要执行一次数据库查询。因此,在设计延迟加载策略时,需要仔细考虑其对性能的潜在影响。

3.#{}和${}的区别

在MyBatis框架中,#{}${}都是用来处理动态SQL参数的占位符,它们有明显的区别:

  1. #{}

    • 预编译处理#{}符号用于预编译参数标记,MyBatis会将#{}替换成 PreparedStatement 中的占位符?,并在执行SQL时通过PreparedStatement接口的setXXX方法来设置参数值。
    • 安全性:由于采用了预编译机制,MyBatis能够自动对传入的参数进行适当地转义处理,从而有效地防止SQL注入攻击。
    • 类型安全:MyBatis可以根据参数类型自动转换并正确处理,例如对于日期、数字类型的参数无需手动添加引号。
  2. ${}

    • 字符串替换${}符号则表示字符串替换,MyBatis会直接将${}内的变量内容原样替换到SQL语句中,不做任何转义或类型处理。
    • 安全性较低 :因为没有预编译和转义处理,如果用户提供的数据未经充分验证或过滤,使用${}可能导致SQL注入风险。
    • 适用场景${}通常用于那些确实需要原样输出到SQL语句中的情况,例如动态构造表名或列名,但在这种情况下,开发者需要自行确保这些动态部分的安全性。

综上所述,一般建议尽可能使用#{}来处理动态参数,因为它更安全、更易于处理不同类型的数据,并且有助于提高SQL执行效率(由于预编译SQL语句仅需编译一次,后续只需替换参数即可执行)。而${}应当谨慎使用,并仅限于确实需要直接插入SQL文本而不涉及用户输入或者不受信任数据的情况下。

相关推荐
Xzh04234 分钟前
AI Agent 学习路线(Java 后端方向)
java·人工智能·学习
Cloud_Shy61828 分钟前
解读《Effective Python 3rd Edition》:从练气到老魔(第五章 Item 33 - 35)
开发语言·人工智能·笔记·python·学习方法
星恒随风33 分钟前
C++ 类和对象入门(五):初始化列表、explicit 和 static 成员详解
开发语言·c++·笔记·学习·状态模式
艾利克斯冰1 小时前
Java 设计模式-行为型模式(更新中)
java·开发语言·设计模式
倒霉蛋小马1 小时前
Java新特性:record关键字
java·开发语言
折哥的程序人生 · 物流技术专研1 小时前
《Java 100 天进阶之路》第95篇:消息队列基础(RocketMQ/Kafka)(2026版)
java·面试·kafka·rocketmq·java-rocketmq·求职招聘
budingxiaomoli1 小时前
Spring日志
java·开发语言
牛油果子哥q1 小时前
【C++ STL vector】C++ STL vector 终极精讲:动态数组底层原理、两倍扩容机制、迭代器失效、增删查改、性能剖析与工程避坑指南
开发语言·c++
IT空门:门主1 小时前
Spring 注入三剑客:@Resource、@Autowired、@RequiredArgsConstructor 到底该用哪个?
java·后端·spring
贩卖黄昏的熊2 小时前
flex 布局快速梳理
开发语言·javascript·css3·html5