1、Mybatis的优缺点

MyBatis是一个可以自定义SQL、存储过程和高级映射的持久层框架,它内部封装了JDBC,开发时只需要关注SQL语句本身。程序员直接编写原生态SQL,可以严格控制sql执行性能,灵活度高。
优点:
1、mybatis是基于SQL语句编程,相对灵活,不会对应用程序或者数据库的现有设计造成任何的影响。mybatis中的sql语句一般写在xml对应的mapper.xml配置文件中,便于统一管理.
2、与JDBC相比,代码量明显减少,消除了JDBC大量冗余的代码,不需要手动开关连接。
3、很好的能与不同的数据库兼容(mysql、Oracle等)
4、能与Spring很好的集成(设计的初衷)
5、提供映射标签,支持对象与数据库的ORM字段关系映射(ResultMap),提供对象关系映射标签,支持对象关系组件维护。
缺点:
1、基于mybatis的SQL语句编写工作量比较大,尤其是当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。
2、SQL语句依赖于数据库,导致数据库的移植性比较差

2、Mybatis和Hibernate的区别?

1、开发工作量方法:
hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。
2、sql优化方法:
由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。而hibernate的sql很多都是自动生成的,无法直接维护sql;虽有hql,但功能还是不及sql强大,见到报表等变态需求时,hql也歇菜,也就是说hql是有局限的;
3、对象管理:
Hibernate是完整的对象/关系映射解决方案,它提供了对象状态管理的功能,使开发者不再需要理会底层数据库系统的细节。也就是说,Hibernate采用更加直接,更加自然的面向对象来持久化Java应用中的数据。换句话说,Hibernate更加注重对象的状态。
4、缓存机制:
MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。
而Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。
5、数据库移植能力:
hibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库(Oracle、MySQL等)的耦合性,而mybatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写sql的方法,如果sql不具通用性而用了很多某数据库特性的sql语句的话,移植性也会随之降低很多,成本很高。

3、#{}和${}的区别是什么?

{}是SQL预编译处理,是占位符;${}是字符串替换,是拼接符
1、mybatis在处理#{}时,会将sql中#{}替换成?号,调用PreparedStatement来赋值;
2、mybatis在处理${}时,就是把${}的值替换成变量的值,调用传入的变量Statement来赋值;
3、#{}的变量替换实在DBMS中,变量替换后,#{}对应的变量自动加上单引号;
4、${}的变量替换是在DBMS外,变量替换后,${}对应的变量不会加上单引号;
5、使用#{}可以有效的防止SQL的注入,保证系统的安全性。
如何选择#{}还是${}:
1、为了保证系统的安全性,能用#{}尽量用#{};
2、表名做参数时,或者order by排序时用${};
3、传参时参数使用@Param(“”)注解,@Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值(相当于又加了一层密),正确的将参数传入sql语句中(一般通过#{}的方式,${}会有sql注入的问题)。如下:
Role selectById(@Param(“id”) String id);
List selectByNameAndOrgId(@Param(“name”) String name, @Param(“orgId”) String orgId);

4、简述MyBatis的插件运行原理,以及如何编写一个插件?

实现MyBatis提供的接口来实现自定义插件,然后在插件的拦截方法内拦截待执行的SQL,最后重写SQL。
mybatis可以编写针对Executor、StatementHandler、ParameterHandler、ResultSetHandler四个接口的插件,主要通过使用JDK的动态代理为需要拦截的接口生成代理对象,然后实现接口的拦截方法,所以当执行需要拦截的接口方法时,会进入拦截方法(AOP面向切面编程的思想),主要步骤为:
1、编写一个实现Intercepror接口的实现类
2、设置插件的签名,主要是通过添加@Intercepts注解,其中type表示要拦截的目标对象,method表示要拦截的方法,args表示要拦截方法的参数。
3、在执行目标方法之前或之后编写插件的业务逻辑,比如我们的分页插件
4、将插件注册到全局配置文件中。

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

1.使用resultMap标签,定义数据库列名和对象属性名之间的映射关系。
1.1、id为定义了一个唯一标识,type对应的java实体对象
1.2、id属性定义java实体id即主键,result标签定义java实体对象其他属性,column属性为数据库列名,property属性为对应的java实体对象属性名
image.png
2.使用sql列的别名功能,将列的别名书写为对象属性名。
3.有了列名与属性名的映射关系后,MyBatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回。

6、谈谈Mybatis的一级缓存和二级缓存

Mybatis的缓存可分为一级缓存和二级缓存,一级缓存默认是放在sqlsession中的,默认就有。二级缓存放在它的命名空间里,默认是不打开的。
一级缓存是SqlSession级别,缓存的是SqlSession对象。在SQL语句、参数都相同的情况下,我们使用同一个SqlSession对象调用同一个Mapper方法的时候,只需要执行一次SQL,因为在第一次执行Mapper方法后。Mybatis会将其缓存起来,后面查询的时候如果参数,SQL语句相同就会直接取缓存的数据,而不会再去查询数据库,这样大大提高了查询效率。当关闭一个sqlsession,对应的一级缓存也就关闭。
一级缓存中每个sqlSession的有一个Executor,每个Executor都有一个Local Cache。当用户发起数据库查询时,mybatis会根据当前执行的语句生成一个MappedStatement,在Local Cache进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入Local Cache,最后返回结果给用户。
image.png
二级缓存:默认不开启,基于namespace,同一个namespace下的多个SQLSession会公用一个缓存,二级缓存同样是使用HashMap就行数据存储,对比一级缓存,二级缓存作用域更大,可跨越多个SQLSession。

7、使用MyBatis的mapper接口调用时有哪些要求?

  1. - Mapper 接口方法名和 mapper.xml 中定义的每个 sql id 相同;
  2. - Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql parameterType 的类型相同;
  3. - Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql resultType 的类型相同;
  4. - Mapper.xml 文件中的 namespace 即是 mapper 接口的类路径。

8、Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别?

mybatis不仅可以执行一对一、一对多的关联查询,还可以执行多对一、多对多的关联查询,多对一的本质是在一对一的基础上将selectOne()改为selectList()、多对多的本质是在一对多的基础上将selectone()改为selectlist()。
实现方式:
关联对象查询有两种实现方式,一种是单独发送一个sql去查询关联对象,赋给主对象,然后返回主对象。
另一种是使用嵌套查询,嵌套查询的含义为使用join查询,一部分列是A对象的属性值,另外一部分列是关联对象B的属性值,好处是只发一个sql查询,就可以把主对象和其关联对象查出来。

9、通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应, 请问,这个 Dao 接口的工作原理是什么?Dao 接口里的方法, 参数不同时,方法能重载吗?

Dao 接口即 Mapper 接口。接口的全限名,就是映射文件中的 namespace 的值;接口的方法名,就是映射文件中 Mapper 的 Statement 的 id 值;接口方法内的参数,就是传递给 sql 的参数。Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MapperStatement。在 Mybatis 中,每一个标签,都会被解析为一个MapperStatement 对象。
Mapper 接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。Mapper 接口的工作原理是 JDK 动态代理,Mybatis 运行时会使用 JDK动态代理为 Mapper 接口生成代理对象 proxy,代理对象会拦截接口方法,转而执行 MapperStatement 所代表的 sql,然后将 sql 执行结果返回。

10、Mybatis映射文件中,如果A标签通过include引用了B标签的内容,请问,B标签能否定义在A标签的后面,还是说必须定义在A标签的前面?

  1. 虽然Mybatis解析Xml映射文件是按照顺序解析的,但是,被引用的B标签依然可以定义在任何地方,Mybatis都可以正确识别。
    2. 原理是,Mybatis解析A标签,发现A标签引用了B标签,但是B标签尚未解析到,尚不存在,此时,Mybatis会将A标签标记为未解析状态,然后继续解析余下的标签,包含B标签,待所有标签解析完毕,Mybatis会重新解析那些被标记为未解析的标签,此时再解析A标签时,B标签已经存在,A标签也就可以正常解析完成了。

    11、Mybatis基本原理

    image.png
    step1:创建加载核心配置文件的inputStream流
    step2:根据mybatis相关核心配置文件由SqlSessionFactoryBuilder.build(inputStream)构建SqlSessionFactory
    step3:获取到sqlSessionFactory后就可以通过定义好的接口方法获取一个sqlSession,从而进行数据库交互。

    • 数据库操作是通过Executor执行器去执行,内部执行原理是jdbc封装后的数据库操作
    • 每一个标签,都会被解析为一个MapperStatement 对象。
    • Mapper 接口的工作原理是 JDK 动态代理,Mybatis 运行时会使用 JDK动态代理为 Mapper 接口生成代理对象 proxy,代理对象会拦截接口方法,转而执行 MapperStatement 所代表的 sql,然后将 sql 执行结果返回。