关于mybatis:三天吃透mybatis面试八股文

56次阅读

共计 5636 个字符,预计需要花费 15 分钟才能阅读完成。

本文曾经收录到 Github 仓库,该仓库蕴含 计算机根底、Java 根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享 等外围知识点,欢送 star~

Github 地址:https://github.com/Tyson0314/Java-learning


Mybatis 是什么?

  • MyBatis 框架是一个开源的数据长久层框架。
  • 它的外部封装了通过 JDBC 拜访数据库的操作,反对一般的 SQL 查问、存储过程和高级映射,简直打消了所有的 JDBC 代码和参数的手工设置以及后果集的检索。
  • MyBatis 作为长久层框架,其次要思维是将程序中的大量 SQL 语句剥离进去,配置在配置文件当中,实现 SQL 的灵便配置。
  • 这样做的益处是将 SQL 与程序代码拆散,能够在不批改代码的状况下,间接在配置文件当中批改 SQL。

ORM 是什么

ORM(Object Relational Mapping),对象关系映射,是一种为了解决关系型数据库数据与简略 Java 对象(POJO)的映射关系的技术。简略的说,ORM 是通过应用形容对象和数据库之间映射的元数据,将程序中的对象主动长久化到关系型数据库中。

Mybatis 和 Hibernate 的区别?

次要有以下几点区别:

  1. Hibernate 的 开发难度 大于 MyBatis,次要因为 Hibernate 比较复杂,宏大,学习周期比拟长。
  2. Hibernate 属于 全自动ORM 映射工具,应用 Hibernate 查问关联对象或者关联汇合对象时,能够依据对象关系模型间接获取,所以它是全自动的。而 Mybatis 在查问关联对象或关联汇合对象时,须要手动编写 sql 来实现,所以,称之为半自动 ORM 映射工具。
  3. 数据库扩展性 的区别。Hibernate 与数据库具体的关联在 XML 中,所以 HQL 对具体是用什么数据库并不是很关怀。MyBatis 因为所有 sql 都是依赖数据库书写的,所以扩展性、迁移性比拟差。
  4. 缓存机制 的区别。Hibernate 的二级缓存配置在 SessionFactory 生成配置文件中进行具体配置,而后再在具体的表对象映射中配置那种缓存。MyBatis 的二级缓存配置都是在每个具体的表对象映射中进行具体配置,这样针对不同的表能够自定义不同的缓冲机制,并且 MyBatis 能够在命名空间中共享雷同的缓存配置和实例,通过 Cache-ref 来实现。
  5. 日志零碎欠缺性 的区别。Hibernate 日志零碎十分健全,波及宽泛,而 Mybatis 则除了根本记录性能外,性能单薄很多。
  6. sql 的优化上,Mybatis 要比 Hibernate 不便很多。因为 Mybatis 的 sql 都是写在 xml 里,因而优化 sql 比 Hibernate 不便很多。而 Hibernate 的 sql 很多都是主动生成的,无奈间接保护 sql;总之写 sql 的灵便度上 Hibernate 不迭 Mybatis。

MyBatis 框架的优缺点及其实用的场合

长处

  1. 与 JDBC 相比,缩小了 50% 以上的代码量。
  2. MyBatis 是易学的长久层框架,玲珑并且简略易学。
  3. MyBatis 相当灵便,不会对应用程序或者数据库的现有设计强加任何影响,SQL 写在 XML 文件里,从程序代码中彻底拆散,升高耦合度,便于对立的治理和优化,并可重用。
  4. 提供 XML 标签,反对编写动静的 SQL,满足不同的业务需要。
  5. 提供映射标签,反对对象与数据库的 ORM 字段关系映射。

毛病

  1. SQL 语句的编写工作量较大,对开发人员编写 SQL 的能力有肯定的要求。
  2. SQL 语句依赖于数据库,导致数据库不具备好的移植性,不能够轻易更换数据库。

实用场景

MyBatis 专一于 SQL 本身,是一个足够灵便的 DAO 层解决方案。对性能的要求很高,或者需要变动较多的我的项目,例如 Web 我的项目,那么 MyBatis 是不二的抉择。

Mybatis 的工作原理

  • 读取 MyBatis 配置文件:mybatis-config.xml 为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,例如数据库连贯信息。
  • 加载映射文件。映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,须要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件能够加载多个映射文件,每个文件对应数据库中的一张表。
  • 结构会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。
  • 创立会话对象:由会话工厂创立 SqlSession 对象,该对象中蕴含了执行 SQL 语句的所有办法。
  • Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将依据 SqlSession 传递的参数动静地生成须要执行的 SQL 语句,同时负责查问缓存的保护。
  • MappedStatement 对象:在 Executor 接口的执行办法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。
  • 输出参数映射:输出参数类型能够是 Map、List 等汇合类型,也能够是根本数据类型和 POJO 类型。输出参数映射过程相似于 JDBC 对 preparedStatement 对象设置参数的过程。
  • 输入后果映射:输入后果类型能够是 Map、List 等汇合类型,也能够是根本数据类型和 POJO 类型。输入后果映射过程相似于 JDBC 对后果集的解析过程。

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

Mybatis 有三种根本的 Executor 执行器,SimpleExecutorReuseExecutorBatchExecutor

SimpleExecutor:每执行一次 update 或 select,就开启一个 Statement 对象,用完立即敞开 Statement 对象。

ReuseExecutor:执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就应用,不存在就创立,用完后,不敞开 Statement 对象,而是搁置于 Map<String, Statement> 内,供下一次应用。简言之,就是重复使用 Statement 对象。

BatchExecutor:执行 update(没有 select,JDBC 批处理不反对 select),将所有 sql 都增加到批处理中(addBatch()),期待对立执行(executeBatch()),它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch()结束后,期待逐个执行 executeBatch()批处理。与 JDBC 批处理雷同。

作用范畴:Executor 的这些特点,都严格限度在 SqlSession 生命周期范畴内。

MyBatis 中接口绑定有几种实现形式?

  1. 通过注解绑定,在接口的办法下面加上 @Select@Update 等注解外面蕴含 Sql 语句来绑定(SQL 语句比较简单的时候,举荐注解绑定)
  2. 通过 xml 外面写 SQL 来绑定, 指定 xml 映射文件外面的 namespace 必须为接口的全路径名(SQL 语句比较复杂的时候,举荐 xml 绑定)

Mybatis 是如何进行分页的?

Mybatis 应用 RowBounds 对象进行分页,它是针对 ResultSet 后果集执行的内存分页,而非物理分页,先把数据都查出来,而后再做分页。

能够在 sql 内间接书写带有物理分页的参数来实现物理分页性能,也能够应用分页插件来实现物理分页。

分页插件的基本原理是什么?

分页插件的基本原理是应用 Mybatis 提供的插件接口,实现自定义插件,在插件的拦挡办法内拦挡待执行的 sql,而后重写 sql(SQL 拼接 limit),依据 dialect 方言,增加对应的物理分页语句和物理分页参数,用到了技术 JDK 动静代理,用到了责任链设计模式。

简述 Mybatis 的插件运行原理

Mybatis 仅能够编写针对 ParameterHandlerResultSetHandlerStatementHandlerExecutor这 4 种接口的插件,Mybatis 应用 JDK 的动静代理,为须要拦挡的接口生成代理对象以实现接口办法拦挡性能,每当执行这 4 种接口对象的办法时,就会进入拦挡办法,具体就是 InvocationHandler 的 invoke()办法,当然,只会拦挡那些你指定须要拦挡的办法。

. 如何编写一个插件?

编写插件:实现 Mybatis 的 Interceptor 接口并复写 intercept()办法,而后再给插件编写注解,指定要拦挡哪一个接口的哪些办法即可,最初在配置文件中配置你编写的插件。

.Mybatis 是否反对提早加载?

Mybatis 仅反对 association 关联对象和 collection 关联汇合对象的提早加载,association 指的就是一对一,collection 指的就是一对多查问。在 Mybatis 配置文件中,能够配置是否启用提早加载lazyLoadingEnabled=true|false

提早加载的基本原理是什么?

提早加载的基本原理是,应用 CGLIB 创立指标对象的代理对象,当调用指标办法时,进入拦截器办法。

比方调用 a.getB().getName(),拦截器 invoke() 办法发现 a.getB()是 null 值,那么就会独自发送当时保留好的查问关联 B 对象的 sql,把 B 查问上来,而后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着实现a.getB().getName() 办法的调用。

当然了,不光是 Mybatis,简直所有的包含 Hibernate,反对提早加载的原理都是一样的。

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

{} 被解析成预编译语句,预编译之后能够间接执行,不须要从新编译 sql。

//sqlMap 中如下的 sql 语句
select * from user where name = #{name};
// 解析成为预编译语句;编译好 SQL 语句再取值
select * from user where name = ?;

${} 仅仅为一个字符串替换,每次执行 sql 之前须要进行编译,存在 sql 注入问题。

select * from user where name = '${name}'
// 传递的参数为 "ruhua" 时, 解析为如下,而后发送数据库服务器进行编译。取值当前再去编译 SQL 语句。select * from user where name = "ruhua";

Mybatis 的预编译

数据库承受到 sql 语句之后,须要词法和语义解析,优化 sql 语句,制订执行打算。这须要破费一些工夫。如果一条 sql 语句须要重复执行,每次都进行语法检查和优化,会节约很多工夫。预编译语句就是将 sql 语句中的 值用占位符代替,行将sql 语句模板化。一次编译、屡次运行,省去了解析优化等过程。

mybatis 是通过 PreparedStatement 和占位符来实现预编译的。

mybatis 底层应用 PreparedStatement,默认状况下,将对所有的 sql 进行预编译,将 #{} 替换为?,而后将带有占位符? 的 sql 模板发送至 mysql 服务器,由服务器对此无参数的 sql 进行编译后,将编译后果缓存,而后间接执行带有实在参数的 sql。

预编译的作用:

  1. 预编译阶段能够优化 sql 的执行。预编译之后的 sql 少数状况下能够间接执行,数据库服务器不须要再次编译,能够晋升性能。
  2. 预编译语句对象能够反复利用。把一个 sql 预编译后产生的 PreparedStatement 对象缓存下来,下次对于同一个 sql,能够间接应用这个缓存的 PreparedState 对象。
  3. 避免 SQL 注入。应用预编译,而其后注入的参数将 不会再进行 SQL 编译。也就是说其后注入进来的参数零碎将不会认为它会是一条 SQL 语句,而默认其是一个参数。

    ## 一级缓存和二级缓存

缓存:正当应用缓存是优化中最常见的办法之一,将从数据库中查问进去的数据放入缓存中,下次应用时不用从数据库查问,而是间接从缓存中读取,防止频繁操作数据库,加重数据库的压力,同时进步零碎性能。

一级缓存是 SqlSession 级别的缓存:Mybatis 对缓存提供反对,默认状况下只开启一级缓存,一级缓存作用范畴为同一个 SqlSession。在 SQL 和参数雷同的状况下,咱们应用同一个 SqlSession 对象调用同一个 Mapper 办法,往往只会执行一次 SQL。因为在应用 SqlSession 第一次查问后,Mybatis 会将后果放到缓存中,当前再次查问时,如果没有申明须要刷新,并且缓存没超时的状况下,SqlSession 只会取出以后缓存的数据,不会再次发送 SQL 到数据库。若应用不同的 SqlSession,因为不同的 SqlSession 是互相隔离的,不会应用一级缓存。

二级缓存是 mapper 级别的缓存:能够使缓存在各个 SqlSession 之间共享。二级缓存默认不开启,须要在 mybatis-config.xml 开启二级缓存:

<!-- 告诉 MyBatis 框架开启二级缓存 -->
<settings>
  <setting name="cacheEnabled" value="true"/>
</settings>

并在相应的 Mapper.xml 文件增加 cache 标签,示意对哪个 mapper 开启缓存:

<cache/>

二级缓存要求返回的 POJO 必须是可序列化的,即要求实现 Serializable 接口。

当开启二级缓存后,数据的查问执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。


最初给大家分享一个 Github 仓库,下面有大彬整顿的 300 多本经典的计算机书籍 PDF,包含 C 语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生 等,能够 star 一下,下次找书间接在下面搜寻,仓库继续更新中~

Github 地址:https://github.com/Tyson0314/java-books

正文完
 0