1、MyBatis 的核心原理,及运行流程
现在开源项目中持久层框架用到最多的基本就是 iBatis、myBatis 和 Hibernate 了。
原理详解:
MyBatis应用程序根据XML配置文件创建SqlSessionFactory,SqlSessionFactory在根据配置,配置来源于两个地方,一处是配置文件,一处是Java代码的注解,获取一个SqlSession。SqlSession包含了执行sql所需要的所有方法,可以通过SqlSession实例直接运行映射的sql语句,完成对数据的增删改查和事务提交等,用完之后关闭SqlSession。
执行流程:
*MyBatis在初始化的时候,会将MyBatis的配置信息全部加载到内存中,使用org.apache.ibatis.session.Configuration实例来维护。使用者可以使用sqlSession.getConfiguration()方法来获取。MyBatis的配置文件中配置信息的组织格式和内存中对象的组织格式几乎完全对应的。
*加载到内存中会生成一个对应的MappedStatement对象,然后会以key="com.louis.mybatis.dao.EmployeesMapper.selectByMinSalary" ,value为MappedStatement对象的形式维护到Configuration的一个Map中。当以后需要使用的时候,只需要通过Id值来获取就可以了。
我们可以看到SqlSession的职能是:
SqlSession根据Statement ID, 在mybatis配置对象Configuration中获取到对应的MappedStatement对象,然后调用mybatis执行器来执行具体的操作。
*MyBatis执行器Executor根据SqlSession传递的参数执行query()方法
Executor.query()方法几经转折,最后会创建一个StatementHandler对象,然后将必要的参数传递给StatementHandler,使用StatementHandler来完成对数据库的查询,最终返回List结果集。
Executor的功能和作用是:
(1、根据传递的参数,完成SQL语句的动态解析,生成BoundSql对象,供StatementHandler使用;
(2、为查询创建缓存,以提高性能
(3、创建JDBC的Statement连接对象,传递给StatementHandler对象,返回List查询结果。
*StatementHandler对象负责设置Statement对象中的查询参数、处理JDBC返回的resultSet,将resultSet加工为List 集合返回
StatementHandler对象主要完成两个工作:
(1. 对于JDBC的PreparedStatement类型的对象,创建的过程中,我们使用的是SQL语句字符串会包含 若干个? 占位符,我们其后再对占位符进行设值。StatementHandler通过parameterize(statement)方法对Statement进行设值;
(2.StatementHandler通过List
StatementHandler 的parameterize(Statement) 方法调用了 ParameterHandler的setParameters(statement) 方法,
ParameterHandler的setParameters(Statement)方法负责 根据我们输入的参数,对statement对象的 ? 占位符处进行赋值。
StatementHandler的List
从MyBatis代码实现的角度来看,MyBatis的主要的核心部件有以下几个:
MyBatis封装了对数据库的访问,把对数据库的会话和事务控制放到了SqlSession对象中。
本题参考博客:https://blog.csdn.net/d12345678a/article/details/53956485
2、MyBatis 与 Hibernate 有什么异同?
hibernate:
1、Hibernate则相对来说较为复杂,学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,怎样用好 Hibernate 方面需要经验和能力都很强才行。
2、Hibernate 会自动生成sql 语句,能够在程序运行时自动生成,能够自动建表,无论到什么机器上,都不需要数据库,都能自动完成迁移;
3、Hibernate 功能强大,数据库无关性好,O/R(对象/关系)映射能力强,Hibernate 对数据库结构提供了较为完整的封装,Hibernate 的O/R Mapping实现了POJO(实体类) 和数据库表之间的映射,以及SQL 的自动生成和执行。程序员往往只需定义好了POJO 到数据库表的映射关系,即可通过 Hibernate 提供的方法完成持久层操作。程序员甚至不需要对SQL 的熟练掌握, Hibernate/OJB 会根据制定的存储逻辑,自动生成对应的SQL 并调用JDBC 接口加以执行;
5、hibernate可移植性好,如一个项目开始使用的是mysql数据库,但是随着业务的发展,现mysql数据库已经无法满足当前的绣球了,现在决定使用Oracle数据库,虽然sql标准定义的数据库间的sql语句差距不大,但是不同的数据库sql标准还是有差距的,那么我们手动修改起来会存在很大的困难,使用hibernate只需改变一下数据库方言即可搞定。用hibernate框架,数据库的移植变的非常方便。
6、当系统属于二次开发,无法对数据库结构做到控制和修改,那myBatis 的灵活性将比 Hibernate 更适合。系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高度优化的SQL语句(或存储过程)才能达到系统性能设计指标。在这种情况下 myBatis 会有更好的可控性和表现。
7、涉及到大数据的系统使用Mybatis比较好,因为优化较方便。涉及的数据量不是很大且对优化没有那么高,可以使用hibernate。
mybatis:
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
mybatis的优点:
MyBatis框架的缺点:
iBatis与myBatis的关系:
iBatis是2002年发起的开放源代码项目,之前一直托管在apache下,于2010年6月16号被谷歌托管,改名为MyBatis,myBatis 与 iBatis 一样,也是一种“半自动化”的ORM实现,共同的优点:
功能架构:
本题参考博客:https://blog.csdn.net/weixin_42131983/article/details/81322029
3、什么是 MyBatis 命名空间?
在 mybatis 中,可以为每个映射文件起一个唯一的命名空间,这样,定义在这个映射文件中的每个 SQL 语句就成了定义在这个命名空间中的一个 id。只要我们能够保证每个命名空间是唯一的,即使在不同映射文件中的语句的 id 相同,也就不会冲突了。
在mybatis中,映射文件中的namespace是用于绑定Dao接口的,即面向接口编程。
当你的namespace绑定接口后,你可以不用写接口实现类,mybatis会通过该绑定自动
帮你找到对应要执行的SQL语句,如下:
假设定义了IArticeDAO接口
public interface IArticleDAO
{
List selectAllArticle();
}
对于映射文件如下:
请注意接口中的方法与映射文件中的SQL语句的ID一一对应 。
则在代码中可以直接使用IArticeDAO面向接口编程而不需要再编写实现类。
本题参考博客:https://blog.csdn.net/suyu_yuan/article/details/51329144
4、MyBatis 中如何进行 Mapper 的动态代理?
UserMapper是一个接口 它并没有实现类,为什么接口可以直接使用呢? 那是因为MyBbatis使用了JDK动态代理机制动态生成了代理类
采用Mapper动态代理方法只需要编写相应的Mapper接口(相当于Dao接口),那么Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:
1、Mapper.xml文件中的namespace与mapper接口的全类名相同。
2、Mapper接口方法名和Mapper.xml中定义的每个statement的id相同。
3、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同。
4、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。
此处参考博客:https://blog.csdn.net/xiaokang123456kao/article/details/66476828
源码分析:
*Mybatis关于包装Mapper的代码都在org.apache.ibatis.binding 这个包下面。其中有4个类:
MapperRegistry 类是注册Mapper接口与获取代理类实例的工具类。
*类的getMapper方法里面最后会去调用MapperProxyFactory类的newInstance方法。在调用getMapper方法前会初始化MapperProxyFactory,它是创建Mapper代理对象的工厂
*在这里创建了MapperProxy对象 这个类实现了JDK的动态代理接口 InvocationHandler
*从缓存中获得执行方法对应的MapperMethod类实例。如果MapperMethod类实例不存在的情况,创建加入缓存并返回相关的实例。最后调用MapperMethod类的execute方法。
到这里我们可以看到,getMapper方法就是用来获得相关的数据操作类接口。而事实数据操作类邦定了动态代理。所以操据操作类执行方法的时候,会触动每个方法相应的MapperProxy类的invoke方法。所以invoke方法返回的结果就是根据操作类执行方法的结果。这样子我们就知道最后的任务交给了MapperMethod类实例。
*MapperMethod类里面有俩个成员:SqlCommand类和MethodSignature类。从名字上我们大概的能想到一个可能跟SQL语句有关系,一个可能跟要执行的方法有关系。事实也是如此。
上面使用一个内部类SqlCommand来封装底层的增删改查操作,确切来讲这一部分的内容跟XxxMapper的XML配置文件里面的select节点、delete节点等有关。我们都会知道节点上有id属性值。那么MyBatis框架会把每一个节点(如:select节点、delete节点)生成一个MappedStatement类。要找到MappedStatement类就必须通过id来获得。有一个细节要注意:代码用到的id = 当前接口类 + XML文件的节点的ID属性。
*我们可以回头去找一找在什么时候增加了MappedStatement类。上面之所以可以执行是建立在XML配置信息都被加载进来了。所以MappedStatement类也一定是在加载配置的时候就进行的。请读者们自行查看一下MapperBuilderAssistant类的addMappedStatement方法——加深理解。SqlCommand类的name成员和type成员我们还是关注一下。name成员就是节点的ID,type成员表示查寻还是更新或是删除。至于MethodSignature类呢。他用于说明方法的一些信息,主要有返回信息。
小知识:反射调用的最大好处就是配置性大大提高,就如同Spring IOC容器一样,我们可以给很多配置参数,使得java应用程序能够顺利运行起来,大大提高java的灵活性和可配置性,降低模块之间的耦合。动态代理就是基于反射实现的。JAVA自带的动态代理是基于java.lang.reflect.Proxy、java.lang.reflect.InvocationHandler两个类来完成的,使用了JAVA反射机制,通常使用下面方法创建代理对象: Object proxy = Proxy.newProxyInstance(定义代理对象的类加载器,要代理的目标对象的归属接口数组,回调接口InvocationHandler)
本题参考博客:https://blog.csdn.net/xiaokang123456kao/article/details/76228684
也可查看我的另一篇博客https://blog.csdn.net/jinhaijing/article/details/84314576,查看具体完整的源码流程
建议可以看看https://blog.csdn.net/xubaifu/article/details/78831147这篇博文,看看自己怎么实现jdk和cglib的动态代理。对于理解mybatis中的动态代理有好处。
5、MyBatis 中如何定义别名查询?
非自定义别名,所有javaJDK中的类都定义了别名,别名是类名不区分大小写: map 替换java.util.Map,如果是包装类,还可以使用基本数据类型:int 替换java.lang.Integer
自定义别名:
mapper.xml中可以使用:
6、MyBatis 的结果集 resultMap 可以定义哪些类型?
resultmap是mybatis中最复杂的元素之一,它描述如何从结果集中加载对象,主要作用是定义映射规则、级联的更新、定制类型转化器。
比如查询对象中有集合,或者对象时,此时就需要用到resultMap来适配结果。
association 一对一级联
collection 一对多级联
注:此处,用到了分步查询,如果还需要配置延迟加载(也叫懒加载和按需加载),在全局文件中还需要配置
关于分步查询和延迟加载可参考博客:https://blog.csdn.net/jinhaijing/article/details/84173959
7、MyBatis 是如何进行分页的?分页插件的原理是什么?
mybatis原生也是支持分页的,但为了与数据库语法解耦,实现的是逻辑分页,首先将所有结果查询出来,然后通过计算offset和limit,只返回部分结果,操作在内存中进行,所以也叫内存分页,当数据量比较大的时候,肯定是不行的,核心类叫Rowbounds
使用原生分页方法:
给接口中传入RowBounds rowBounds = new RowBounds(0, 5);
listPo = userPoMapper.selectByExample(type,rowBounds);
List
注:PageHelper的使用
1、sqlsession: sqlsession是一次与数据库的会话。在你每次访问数据库时都需要创建它(当然并不是说在sqlsession里只能执行一次sql,你可以执行多次,当一旦关闭了Sqlsession就需要重新创建它)。sqlsession只能由SqlsessionFactory的openSession方法来完成创建
2、executor: 通过源码我们可以看到:executor其实只是DefaultSqlSession的一个属性,而executor的每个操作都需要一个对象,那就是MappedStatement
3、MappedStatement: 这个东西个人看来就是用来封装sql和返回结果的,我们很熟悉的可以看到id(个人猜想可能是mapper.xml中的那个id,即具体执行的是哪个sql)、parameterMap(应该就是mapper.xml中的那个parameterMap,即sql中变量的类型)、 resultMaps(大概就是你需要的返回对象类型)
可参考博客:https://blog.csdn.net/leozhou13/article/details/50394242看怎么自己制作一个分页插件
8、MyBatis 中什么是逻辑分页,什么是物理分页,分别有什么优缺点?
逻辑分页:将所有结果查询出来,然后通过计算offset和limit,只返回部分结果,操作在内存中进行,所以也叫内存分页,当数据量比较大的时候,肯定是不行的,核心类叫Rowbounds
物理分页:修改最后的执行sql,增加xi相应的分页内容,是基于拦截器实现的
具体可看上一题
9、MyBatis 怎样进行事务管理?
mybatis支持两种事务类型,分别为JdbcTransaction和ManagedTransaction。
Mybatis定义了一个事务类型接口Transaction,JdbcTransaction和ManagedTransaction两种事务类型都实现了Transaction接口。
具体可参考博客:https://blog.csdn.net/majinggogogo/article/details/72026693
10、比较 MyBatis 和 Hibernate 事务管理的区别
11、MyBatis 框架有哪些注解?
12、MyBatis 如何进行关联关系(一对一,一对多,多对多),以及双向关联关系查询?
13、MyBatis 有几种缓存,获取 Sqlsession 后,查询数据的顺序;MyBatis 中与Hibernate 中获取 session 后,查询数据的顺序有什么区别?
14、简述 MyBatis 的插件运行原理,以及如何编写一个插件
14、MyBatis 怎样处理延迟加载?
15、集成 Spring MVC+Spring+MyBatis 有哪些步骤?
16、什么是 MyBatis 的接口绑定,有什么好处
17、最佳实践中,通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应,请问,这个 Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗?
18、MyBatis 执行批量插入,能返回数据库主键列表吗?
19、MyBatis 动态 SQL 是做什么的?都有哪些动态 SQL?能简述一下动态 SQL 的执行原理
20、MyBatis 是如何将 SQL 执行结果封装为目标对象并返回的?都有哪些映射形式?
21、MyBatis 都有哪些 Executor 执行器?它们之间的区别是什么?
22、MyBatis 中如何指定使用哪一种 Executor 执行器?
30、简述 MyBatis 的 Xml 映射文件和 MyBatis 内部数据结构之间的映射关系?
31、为什么说 MyBatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?
32、Mybatis 如何与 LOG4J 结合打印日志
33、MyBatis 如何执行存储过程
34、Mybatis 数据源管理方式有几种?
35、MyBatis 引入 XXX.mapper 映射文件有几种方式?
36、MyBatis 事务管理有几种方式?
37、什么样的需求使用 mybatis 框架更好?什么样的需求使用 hibernate 框架更好?
38、解释下 DefaultSqlSessionFactory 的作用?
39、解释下 SqlSessionFactoryBuilder 的作用?
40、说出 MyBatis 缓存和 Hibernate 缓存的区别?
41、MyBatis 中 sql 语句执行类型有几种方式?(ExecutorType)
42、MyBatis 中 ObjectFactory 是什么?
43、MyBatis 中 TypeHandler 是什么?