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
,只支持SIMPLE
和BATCH
。
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)。这个代理对象在外部代码首次访问它的方法时,才会触发真正的数据库查询操作。
- 代理对象:MyBatis 使用 CGLIB 或 JDK 动态代理(取决于对象类型是接口还是类)来创建关联对象的代理。
- 触发加载:当程序访问代理对象的任何方法时,代理逻辑会判断该关联对象是否已经被加载。如果还没有加载,代理就会执行实际的 SQL 查询来加载数据,并将结果设置到代理对象中。
- 透明访问:一旦数据被加载,代理对象就会把对它的方法调用委托给实际加载的数据对象,之后的访问就如同直接使用数据对象一样,对使用者来说是透明的。
这种延迟加载的策略允许减少初始化对象时的数据库访问量,特别是对于那些不一定需要立即使用所有数据的场景,可以有效减少资源的消耗,提高应用性能。然而,使用延迟加载时也需要注意,它可能导致 N+1 查询问题,即访问每个对象的关联数据时都要执行一次数据库查询。因此,在设计延迟加载策略时,需要仔细考虑其对性能的潜在影响。
3.#{}和${}的区别
在MyBatis框架中,#{}
和${}
都是用来处理动态SQL参数的占位符,它们有明显的区别:
-
#{}
:- 预编译处理 :
#{}
符号用于预编译参数标记,MyBatis会将#{}
替换成 PreparedStatement 中的占位符?
,并在执行SQL时通过PreparedStatement接口的setXXX
方法来设置参数值。 - 安全性:由于采用了预编译机制,MyBatis能够自动对传入的参数进行适当地转义处理,从而有效地防止SQL注入攻击。
- 类型安全:MyBatis可以根据参数类型自动转换并正确处理,例如对于日期、数字类型的参数无需手动添加引号。
- 预编译处理 :
-
${}
:- 字符串替换 :
${}
符号则表示字符串替换,MyBatis会直接将${}
内的变量内容原样替换到SQL语句中,不做任何转义或类型处理。 - 安全性较低 :因为没有预编译和转义处理,如果用户提供的数据未经充分验证或过滤,使用
${}
可能导致SQL注入风险。 - 适用场景 :
${}
通常用于那些确实需要原样输出到SQL语句中的情况,例如动态构造表名或列名,但在这种情况下,开发者需要自行确保这些动态部分的安全性。
- 字符串替换 :
综上所述,一般建议尽可能使用#{}
来处理动态参数,因为它更安全、更易于处理不同类型的数据,并且有助于提高SQL执行效率(由于预编译SQL语句仅需编译一次,后续只需替换参数即可执行)。而${}
应当谨慎使用,并仅限于确实需要直接插入SQL文本而不涉及用户输入或者不受信任数据的情况下。