本文曾经收录到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