1、请介绍Mybatis框架及优缺点
MyBatis前身是Apache的iBatis,2010年由iBatis更名为MyBatis,目前源码托管在GitHub上。通过程序员自己编写SQL后交给MyBatis进行结果映射,极大的简化了JDBC冗余代码。此外还内置支持缓存、延迟加载、日志、动态SQL等功能。是目前Java项目首选的数据访问层框架
优点:
1、灵活度高。程序员自己编写SQL,可以实现自己想要的结果
2、内置缓存机制。通过缓存机制,大大减少了与数据库交互次数,提升程序运行性能
3、简化代码,与传统JDBC代码相比,去掉了大量的JDBC模板代码,只需要接口的方法声明和mapper.xml配置
4、良好的数据库兼容性。MyBatis几乎支持市场上所有主流的数据库产品
5、支持与Spring整合。目前Java开发中,如果一个框架不能与Spring进行良好的继承,那么这个框架很难被普及。
缺点:
1、需要程序员具备良好的SQL功底。因为MyBatis中所有的SQL都是由程序员手动编写,所以如何写出一个良好的SQL语句称为使用MyBatis框架的最大考验
2、移植性差。SQL是依赖数据库的,不同数据库有不同的SQL语句同,所以在开发时需要选定好所使用的数据库,尽量不要更换数据库。
2、请说一下理解的ORM
ORM(Object Relational Mapping):对象关系映射,是一种程序设计技术。主要思想是通过指定对象和关系型数据库之间的映射关系,可以使程序开发时可以使用面向对象思想操作关系型数据库
ORM是数据库发展速度不及编程语言的产物
3、为什么说MyBatis是半自动ORM框架
自动生成SQL、进行参数设置、结果集映射只要满足三个条件,就是全自动ORM框架
标准ORM框架是只需要把对象传递给ORM框架后,由ORM框架生成SQL语句,填充结果后返回。
但是MyBatis框架需要由程序员手动编写SQL,由MyBatis进行结果填充,所以说MyBatis是半自动化ORM框架。其中的手动编写SQL是不自动的一半,结果填充是自动的一半
4、MyBatis和Hibernate的区别
MyBatis和Hibernate都是目前企业中在使用的数据访问层框架,都是对JDBC的封装,只是MyBatis市场占比要比Hibernate多很多
1、Hibernate是标准的ORM框架,在配置了映射关系后,会由Hibernate自动生成SQL并填充结果。而MyBatis是半自动化ORM框架,需要由程序员手动编写SQL。
2、Hibernate移植性更强。Hibernate只需要配置方言(dialect)就可以切换为所支持的框架。而MyBatis需要修改SQL
3、Hibernate的缓存机制更强。MyBatis的缓存是基于<select>标签的,而Hibernate的缓存是基于缓存中对象的通过OID判断是否缓存数据。并且Hibernate还会自动帮助检查脏数据
4、Hibernate具有更强的日志系统。Hibernate的日志可以记录执行SQL、SQL排版优化、缓存提示、脏数据异常等信息。而MyBatis的日志主要记录执行SQL,参数设置,执行结果缓存操作等。
5、MyBatis灵活度更高。虽然Hibernate也带有SQL方式查询,但是主要使用的还是零SQL方式。MyBatis虽然需要自己写SQL,但这也是MyBatis非常重要的优点,只要具有SQL编写和优化能力,可以写出来更优秀的SQL
6、MyBatis更加简单。MyBatis的学习成体更低,框架更加方便简单。Hibernate功能强大,所以学习成本更大。
5、MyBatis是否必须有接口
MyBatis框架并不要求必须有接口。MyBatis提供了三种引入的方式
1、只编写mapper.xml
2、编写接口和mapper.xml
3、编写接口并在接口方法上使用注解提供SQL
6、MyBatis是如何实现接口和mapper.xml绑定的
是应用动态代理设计模式实现接口和映射文件来绑定的,当获取到接口的时候,会产生接口的动态代理对象,接口里面调用方法的时候,就通过动态代理调用我们真实使用的SQL语句,Mybatis是通过在全局配置文件中指定要扫描的包,在包中提供同名的接口文件和mapper.xml文件,在mapper.xml中namespace指定接口的全限定路径,在标签的id属性值配置为接口中方法名称。
7、MyBatis接口是不支持方法重载
在java的类中是支持方法重载的但是在MyBatis中是不允许方法重载的。
因为在mapper.xml中每一个<select>、<update>、<delete>、<insert>标签的最终存储时都是namespace+id作为key进行存储。如果接口中存在两个同名方法(方法重载),在mapper.xml中也会提供两个同名id。
8、MyBatis中mapper.xml除了<select>、<update>、<delete>、<insert>标签以外还支持哪些标签
在MyBatis的mapper.xml中除了最基本的增加、删除、修改、查看标签以还支持<resultMap>结果集映射、<cache>二级缓存配置、<cache-ref>二级缓存引用、<parameterMap>参数映射、<sql>SQL片段、<selectKey>新增时回填主键、<include>引用SQL和动态SQL的7个标签<if>、<choose>、<trim>、<where>、<set>、<foreach>、<bind>,还有<resultMap>的常用四个子标签<id>、<result>、<collection>、<association>、<discriminator>、<constructor>
9、MyBatis中namespace的作用,有些要求
namespace是mapper.xml中<mapper>标签的属性,定义出当前文件所有的SQL的命名空间,所谓的命名空间就是一个字符串类型的分组名称。
namespace属性必须存在,也不能为空。如果没有配置namespace或者取值为空时会出现BuilderException
多个mapper.xml中允许出现同名的namespace,但是在实际项目中namespace的值都是绑定接口的全限定路径,且一个接口只会对应一个mapper.xml文件。
10、MyBatis中不同的mapper.xml中id是否允许重复
id属性存在的意义是与namespace结合作为SQL的key,每个SQL的key是不允许重复的。所以id是否允许重复和namespace有关系的
namespace量必须配置的属性,且不同的mapper.xml的namespace是可以重复的。
1、如果namespace不同,里面标签的id属性值是可以重复的。
2、如果namespace相同,里面标签的id属性值是不允许重复的。
11、MyBatis的mapper.xml中如何获取方法参数
1、mapper接口方法的参数为单个字面里类型时,可以通过${}和#{}以任意的名称获取参数值。
2、mapper接口方法的参数为多个时,Mybatis会将这些参数放在一个map集合中,以两种方式进行存储,以arg0、arg1...为键,以param1、param1...为值,可以通过${}和#{}以键方式访问获取参数值。
3、mapper接口方法的参数有多个时,可以手动将这些参数放在一个map中存储,只需要通过${}和#{}以map中的key名称获取参数值。
4、mapper接口方法的参数是实体类类型的参数
只需要通过${}和#{}以属性方式访问属性值,即可
5、使用@Param注解命名参数,此时Mybatis会将这些参数放在一个map集合中,以两种方式进行存储
1、以@Param注解的值为键,以参数为值,只需要通过${}和#{}以键的方式访问值,即可
12、MyBatis的mapper.xml中${}和#{}的区别
#{}:解析成占位符?,能防止SQL注入问题
${}:相当于字符串拼接。所以在给列设置值时不要使用${}。如果希望动态设置表名或列名等时可以使用${}
13、MyBatis中结果填充(映射)的几种方式
1、Auto Mapping:当查询表的列名和实体类的属性名相同时,MyBatis直接按照列名填充到属性名中
2、别名方式。如果数据库中表的列名和属性名不相同,可以在查询SQL中通过起别名的方式让别名对应上属性名
3、resultMap方式:也可以通过resultMap的方式明确配置列和属性映射关系。
14、MyBatis中实体类的属性名和列名是否必须相同。
在数据库的命名规范中都是多个单词使用下划线分隔
在java中属性名的命名规范是小驼峰
命名规范的不一致就导致经常出现了属性名和字段名不一致的问题
当名称不一致可以通过别名或resultMap标签人进行映射
所以在MyBatis中实体类的属性名和列名可以不相同
15、MyBatis中实体类是否必须有getter和setter方法
不是的
MyBatis在进行结果填充时和参数获取时优先使用反射获取getter和setter。如果实体类不存在getter和setter方法,会使用反射直接访问类中属性,即使这个属性是private,也可以访问
参数获取时调用getter方法,结果集填充时调用setter方法
16、MyBatis如何实现关联对象查询
1、N+1查询方式(分步查询)
N+1查询方式,在不考虑缓存的情况下,以查询外键表信息举例,假设外键表有N条数据,则需要1条查询外键表的SQL,和N条根据主键查询主键表的SQL
2、多表联合查询方式
多表联合查询方式只需要一条SQL语句
但是N+1查询方式支持延迟加载,而多表联合查询方式不支持
如果关联的是一个对象,使用<resultMap>的<association>进行查询
如果关联的是一个集合,使用<resultMap>的<collection>进行查询
17、MyBatis中如何实现延迟加载
MyBatis中延迟加载只能出现在N+1查询方式(分步查询)。默认是没有开启延迟加载的。
有两种配置办法
1、设置全局开关。在MyBatis全局配置文件中配置两个属性,开启延迟加载
2、在<association>或<collection>中fetchType控制,lazy表示延迟加载,eager表示立即加载
当fetchType和全局开关同时配置是fetchType生效
18、MyBatis的缓存机制
MyBatis中提供了两种缓存,一级缓存和二级缓存。通过缓存可以减少对数据库的访问,提高程序执行性能。
其中一级缓存又称SqlSession缓存,默认开启的,有效范围必须是同一个SqlSession对象,且每次缓存同一个方法中相同的SQL语句。在缓存时把SQL当做Key,查询的结果当做Value进行缓存。当关闭后释放缓存中的内容。
而二级缓存又称SqlSessionFactory缓存,有效范围同一个SqlSessionFactory对象。默认是禁用状态,需要在映射文件中添加<cache>标签启用二级缓存。当SqlSession提交或关闭时把一级缓存的内容放入到二级缓存中。由于在项目SqlSessionFacotry是不关闭的,所以二级缓存内容默认是一直存在,二级缓存中放经常被查询,很少被修改的内容。
每次查询时先判断二级缓存,如果没有,再判断一级缓存,如果也没有,访问数据库
19、MyBatis中执行器有几种
MyBatis的执行器都实现了Executor接口。作用是SQL执行的流程
在MyBatis中执行器共分为三个类型:SimpleExecutor、ReuseExecutor、BatchExecutor
其中SimpleExecutor是默认的执行器类型,每次执行SQL都需要预编译、设置参数、执行。
ReuseExecutor只预编译一次,复用Statement对象,然后设置参数,并执行。
BatchExecutor先预编译,批量执行时设置参数,最后统一提交给数据库执行。
在项目可以通过factory.openSession()方法参数设置执行器类型。通过枚举类型ExecutorType进行设置。
20、说一下MyBatis四大核心接口及执行流程
MyBatis四大核心接口:
Executor:执行器。负责SQL执行过程的总体控制
ParameterHandler:参数处理器,负责SQL语句的参数设置
StatementHandler:负责与JDBC代码的交互,包含prepare预处理、query查询、update增删改操作
ResultSetHandler:结果集处理器。负责把查询结果映射为Java对象
执行流程
21、MyBatis中如何定义一个插件
1、创建一个类实现Interceptor接口,重写接口方法。
intercept()方法表示拦截方法,可以获取到目标对象。能实现获取SQL等。
plugin()插件方法,产生代理对象。
2、在类上添加注解
@Intercepts(value=@Signature(type=StatementHandler.class , method = "prepare",args={Connection.class,integer.class} ))
type:监听目标类或接口。可选值为四大核心接口或实现类
method:监听的目标中方法名称。
22、MyBatis的动态SQL是什么?支持哪些动态SQL标签
动态SQL本质就是SQL语句的拼接。根据不同条件产生不同的SQL语句
在MyBatis中动态SQL标签包含<if>、<choose>...<when>....<otherwise>、<trim>、<where>、<set>、<foreach>、<bind>七组标签。
23、MyBatis支持的日志类型
MyBatis的日志默认是没有开启的。
可以在MyBatis的全局配置文件中<settings>的logImlpl进行配置
按照官方文档说明,共支持6种日志
1、slf4j
2、log4j
3、log4j2
4、Jdk_logging
5、commons_logging
6、stdout_logging
24、MyBatis使用了哪些设计模式?
1、代理模式(Mapper)
2、适配器模式(Log)
3、工厂模式(SqlSession)
4、装饰器模式(CachingExecutor)
5、建造者模式(SqlSessionFactoryBuilder)
6、策略模式(openSession可以控制ExecutorType)
7、模板模式(BaseExecutor)、
8、责任链模式(Interceptor)
25、MyBatis运行原理
MyBatis在运行时,会通过Resources将配置文件的配置信息转化为输入流(InputStream),会把输入类交给XMLConfigBuilder做XML解析和构建,其解析的过程中,是用java的DOM操作做的解析,将解析的结果存储到Configuration中,Configuration是MyBatis储存所有配置信息的一个类,然后将Configuration作为DefaultSqlSessionFactory的构造化参数进行传递和储存,产生SqlSession的工厂,然后根据工厂创建SqlSession对象,在创建的过程是通过DefaultSqlSession实例化的,