MyBatis 基础(面试)

一、介绍MyBatis

  1. 优秀的半ORM 持久层框架,支持定制化SQL、存储过程以及高级映射。
  2. MyBatis 避免了手动设置参数以及获取结果集。

1. 什么是ORM

对象关系映射:一种解决简单Java 对象 与 关系型数据库的映射关系的技术。通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系型数据库中。

2. 为什么是半自动的

  1. MyBatis 在查询关联对象或关联集合对象时,需要手动编写SQL完成,所以称之为半自动的ORM映射工具。
  2. 比如Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以是全自动的。

3. 优缺点

优点:

  1. 基于SQL 语句编程相对比较灵活,SQL 写在XML中与程序解耦,便于统一管理。
  2. 与JDBC 相比不需要手动开启连接,同时也减少了编写大量的代码。
  3. 与各种数据库兼容,能够与Spring 很好的集成。

缺点:

  1. SQL 编写工作量较大,关联表较多时对开发人员编写SQL 语句功底有一定的要求。
  2. SQL 语句依赖于数据库,导致数据库移植性较差,不能随便更换数据库。

二、MyBatis 的核心工作原理及编程步骤

1. MyBatis 的工作原理

  1. 读取MyBatis 的配置文件: mybatis-config.xml 为MyBatis 的全局配置文件,配置了MyBatis 的运行环境等信息。如数据库的连接
  2. 加载映射文件: 映射文件即SQL 映射文件,需要在MyBatis 配置文件中加载。
  3. 构建会话工厂: 通过MyBatis 的环境信息构建工厂SqlSessionFactory。
  4. 创建会话对象: 由会话工厂创建SqlSession 对象,该对象中包含了执行SQL 的所有方法。
  5. Executor 执行器: MyBatis 底层定义了Executor 接口来操作数据库,它将根据SqlSession 传递的参数动态生成需要执行的SQL 语句,同时负责查询缓存的维护
  6. MappedStatement 对象: 在Executor 接口的执行方法中有一个MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储SQL 语句的id、参数等信息。
  7. 输入参数映射: 输入参数类型可以是list、map、pojo 等类型。
  8. 输出结果映射: 输出结果类型可以是list、map、pojo 等类型。
    MyBatis 的工作流程

2. MyBatis 的编程步骤

  1. 创建SqlSessionFacotry;
  2. 通过SqlSessionFactory 创建SqlSession;
  3. 通过SqlSession 执行数据库操作;
  4. 通过session.commit() 提交事务;
  5. 通过session.close() 关闭会话。

3. JDBC 的工作原理

  1. 加载驱动,建立连接;
  2. 创建Statement 语句对象;
  3. 执行SQL 语句;
  4. 处理结果集;
  5. 关闭连接。

4. MyBatis 有哪些Executor 执行器?

有SimpleExecutor、ReuseExecutor、BatchExecutor
SimpleExecutor: 每执行一次update 或select,就开启一个Statement 对象,用完立即关闭;
ReuseExecutor: 执行update 或select,以sql 作为key 查找Statement 对象,存在就使用不存在就创建,用完后不关闭Statement 对象;
BatchExecutor: 执行update(批处理不支持select),将所有的SQL 都添加到批处理中(addBatch() ),等待统一执行(executeBatch( )),它缓存了多个Statement 对象,每个Statement 对象都是addBatch( ) 完毕后等待逐一执行executeBatch( ) 批处理。

三、为什么需要预编译?

  1. 定义:SQL 预编译指的是数据库驱动在发送SQL 语句和参数 给数据库管理系统之前对SQL 进行编译,这样数据库管理系统执行SQL 时就不需要重新编译。
  2. 为啥需要:JDBC 中使用对象PreparedStatement 来抽象预编译语句。预编译阶段可以优化SQL 的执行。多数情况下预编译的SQL 数据库管理系统可以直接运行,DBMS 不需要再次编译,越复杂的SQL,编译的复杂度越大,预编译阶段可以合并多次操作为一个操作。预编译后产生的PreparedStatement 对象缓存下来,下次对于同一个SQL 可以直接使用。MyBatis 默认情况下将所有的SQL 进行预编译。

四、MyBatis 是否支持延迟加载

  1. MyBatis 只支持association 关联对象和collection 关联集合对象的延迟加载。association 指的是一对一,collection 指的是一对多查询。在MyBatis 配置文件中,通过lazyLoadingEnable = true/false 来配置。
  2. 延迟加载的原理:使用CGLIB 创建目标对象的代理对象,当调用目标对象时进入拦截器方法。如调用 a.getB.getName(),拦截器invoke() 方法发现 a.getB() 是null 值,那么就会单独发送事先保存好的查询关联B 对象的SQL,把B 查询上来再调用setB(b) ,这样a 对象的 b 属性就有值了,接着完成 a.getB.getName() 方法调用。

五、#{} 和${} 的区别

  1. #{ } 是占位符,预编译处理;${ } 是拼接符,字符串替换,没有预编译处理。
  2. #{ } 可以有效防止SQL 注入;${ } 不能防止SQL 注入。
  3. MyBatis 在处理#{ } 时,#{ } 传入的参数以字符串传入,会将SQL 中的#{ } 替换为?,调用PreparedStatement 的set 方法来赋值。

六、模糊查询like 语句的写法

  1. “%” #{like} “%” ,需要注意因为#{ }在解析成sql 时会自动在变量外侧加单引号’ ’ ,所以%需要使用双引号不能使用单引号。
  2. CONCAT(’%’, #{like}, ‘%’) 使用CONCAT 函数,推荐写法!!!
  3. 使用bind 标签
<select id="selectUserByBind" resultType="com.po.MyUser" parameterType= "com.po.MyUser">
    <!-- bind 中的 name 是 pojo 的属性名-->
    <bind name="param_name" value="'%' + name + '%'"/>
        select * from user where name like #{param_name}
</select>

CONCAT( ) 方法是MySQL 的函数,Oracle 的连接符号是“||”,这样不利于代码的移植。MyBatis 提供了 bind 标签解决了这一问题。

七、Mapper 如何传递多个参数

  1. 顺序传参法

    <select id="selectUser" resultMap="UserResultMap">
        select * from user
        where user_name = #{0} and dept_id = #{1}
    </select>
    

    #{}里面的数字代表传入参数的顺序。

  2. @Param(" ") 注解传参法

  3. Map 传参及pojo 传参法
    方法2 和方法3 都是使用#{属性名} 来接收参数

八、Dao 接口的工作原理是什么?Dao 接口里的方法参数不同时方法能重载吗?

接口的全限名就是映射文件namespace 的值,接口的方法名就是映射文件MappedStatement 的id 值,接口方法内的参数就是传递给SQL 的参数。

当调用接口方法时,接口的权限名 + 方法名拼接成字符串可以唯一定位一个MappedStatement ,MyBatis 中,<select>、<insert>、<update>、<delete> 标签都会别解析为一个MappedStatement 对象。

因为权限名 + 方法名 的保存和寻找策略,dao 接口里的方法是不能重载的。

Dao 接口的工作原理是JDK 动态代理,MyBatis 会使用JDK 动态代理为Dao 接口生成代理对象,代理对象会拦截接口方法,转而执行MappedStatement 所代表的SQL,然后将执行的结果返回。

九、不同的XML 映射文件id 是否可以相同?

如果xml 配置了namespace,则id 是可以重复的;如果没有配置namespace ,则id 是不能重复的;毕竟namespace 不是必须的。

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

使用<resultMap> 标签,逐一定义列名和对象属性名之间的映射关系

使用sql 的别名,将别名书写为对象属性名。对象属性名一般是小写,但是列名不区分大小写,MyBatis 会忽略列名大小写。把T_NAME 写成NaMe,MyBatis 照样可以正常工作。

有了列名和属性名的对象关系,MyBatis 通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性是无法完成赋值的。

十一、MyBatis实现一对一,一对多有几种方式,怎么操作的?

有联合查询和嵌套查询。联合查询是几个表联合查询,只查询一次,通过在resultMap里面的association,collection节点配置一对一,一对多的类就可以完成

嵌套查询是先查一个表,根据这个表里面的结果的外键id,去再另外一个表里面查询数据,也是通过配置association,collection,但另外一个表的查询通过select节点配置。

十二、动态SQL 是什么,有哪些动态SQL 标签?

MyBatis 动态SQL 可以让我们在XML 映射文件内,以标签的形式编写动态SQL,完成逻辑判断和动态SQL 拼接功能。

MyBatis 提供了9种动态SQL 标签。
set、where、if、when、foreach、choose、otherwise、trim、bind

执行原理:使用OGNL 从SQL 参数对象中计算表达式的值,根据表达式动态的拼接SQL,以此来完成动态SQL 的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值