Mybatis
什么是MyBatis?优缺点及适用场景
Mybatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作, 开发时只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动.创建连接.创 建 statement 等繁杂的过程。程序员直接编写原生态 sql,可以严格控制 sql执 行性能,灵活度高。
MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映 射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取 结果集。
通过 xml 文件或注解的方式将要执行的各种 statement 配置起来, 并通过 java 对象和 statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回(从执 行 sql 到返回 result 的过程)。
优点:
-
简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
-
基于 SQL 语句编程,相当灵活,不会对应用程序或者数据库的现有设 计造成任何影响;SQL 写在 XML 里,解除 sql 与程序代码的耦合,便于统一管 理;提供 XML 标签,支持编写动态 SQL 语句,并可重用。
-
与 JDBC 相比,减少了 50%以上的代码量,消除了 JDBC 大量冗余的 代码,不需要手动开关连接;
-
很好的与各种数据库兼容(因为 MyBatis 使用 JDBC 来连接数据库, 所以只要 JDBC 支持的数据库 MyBatis 都支持)。
-
能够与 Spring 很好的集成;
-
提供映射标签,支持对象与数据库的 ORM 字段关系映射;提供对象 关系映射标签,支持对象关系组件维护
缺点:
- 1、编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。
- 2、SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。
- 3、框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
适用场景:
- MyBatis 专注于 SQL 本身,是一个足够灵活的 DAO 层解决方案。
- 对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis 将是不错的选择
mybatis的一级缓存和二级缓存:
缓存的作用:使用缓存, 我们可以避免频繁的与数据库进行交互, 尤其是在查询越多、缓存命中率越高的情况下, 使用缓存对性能的提高更明显。mybatis 也提供了对缓存的支持, 分为一级缓存和二级缓存。 但是在默认的情况下, 只开启一级缓存
MyBatis与Hibernate有哪些不同
- Mybatis 和 hibernate 不同,它不完全是一个ORM 框架,Mybatis 是一个半 ORM(对象关系映射)框架,因为 MyBatis需要程序员自己编写 Sql 语句。
- Mybatis 直接编写原生态 SQL,可以严格控制 SQL 执行性能,灵活 度高,非常适合对关系数据模型要求不高的软件开发
- Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用 Hibernate 开发可以节省很多代码,提高效率。
#{}和${}的区别
#{} 是 sql 的参数占位符,${}是 Properties ⽂件中的变量占位符
Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法来赋值;
Mybatis 在处理 时 , 就 是 把 {}时,就是把 时,就是把{}替换成变量的值。使 用#{}可以有效的防止 SQL 注入,提高系统安全性。
MyBatis是如何进行分页的?分页插件的原理是什么?
Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执 行的内存分页,而非物理分页。可以在 SQL 内直接书写带有物理分页的参数来 完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义插件, 在插件的拦截方法内拦截待执行的 SQL,然后重写 SQL,根据 dialect 方言,添 加对应的物理分页语句和物理分页参数。
实现 Mybatis 的 Interceptor 接⼝并复写 intercept() ⽅法,然后在给插件编写注解,指定要拦截哪⼀个接⼝的哪些⽅法即可,记住,别忘了在配置⽂件中配置你编写的插件。
MyBatis的动态SQL
答:Mybatis 动态 sql 可以让我们在 Xml 映射⽂件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能,Mybatis 提供了 9 种动态 sql 标签
trim|where|set|foreach|if|choose|when|otherwise|bind 。
其执⾏原理为,使⽤ OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql,以此来完成动态 sql 的功能。
MyBatis是是如何将sql执行结果封装为目标对象并返回的?都有哪些映射方式?
第⼀种是使⽤ 标签,逐⼀定义列名和对象属性名之间的映射关系。
第⼆种是使用标签和 SQL 列的别名功能,将列的别名书写为 对象属性名。(⽐如 T_NAME AS NAME,对象属性名⼀般是 name,⼩写,但是列名不区分⼤⼩写,Mybatis 会忽略列名⼤⼩写,智能找到与之对应对象属性名),有了列名与属性名的映射关系后,Mybatis 通过反射创建对象,同时使⽤反射给对象的属性逐⼀赋值并返回,那些找不到映射关系的属性,是⽆法完成赋值的。
XML映射文件中,除了常见的select|insert|update|dalete标签之外,还有哪些标签
还有很多其他的标签, 、 、 、 、 ,加上动态 sql 的 9个标签, trim|where|set|foreach|if|choose|when|otherwise|bind 等,其中为 sql ⽚段标签,通过 标签引⼊ sql ⽚段, 为不⽀持⾃增的主键⽣成策略标签。
Mybatis的 Xml映射⽂件中,不同的Xml映射⽂件id是否可以重复?
不同的 Xml 映射⽂件,如果配置了 namespace,那么 id 可以重复;如果没有配置namespace,那么 id 不能重复;
原因就是 namespace+id 是作为 Map<String, MappedStatement> 的 key 使⽤的,如果没有namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。有了 namespace,⾃然 id 就可以重复,namespace 不同,namespace+id ⾃然也就不同。
为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?
Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合 对象时,可以根据对象关系模型直接获取,所以它是全自动的。而 Mybatis 在查询关联对 象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具
MyBatis能执行一对一,一对多的关联查询吗?都有哪些实现方式?
Mybatis 不仅可以执⾏⼀对⼀、⼀对多的关联查询,还可以执⾏多对⼀,多对多的关联查询,多对⼀查询,其实就是⼀对⼀查询,只需要把 selectOne() 修改为 selectList() 即可;多对多查询,其实就是⼀对多查询,只需要把 selectOne() 修改为 selectList() 即可。
通过关联对象查询,有两种实现⽅式,⼀种是单独发送⼀个 sql 去查询关联对象,赋给主对象,然后返回主对象。另⼀种是使⽤嵌套查询,嵌套查询的含义为使⽤ join 查询,先 查一个表,根据这个表里面的 结果的外键 id,去再另外一个表里面查询数据,也是 通过配置 collection,但另外一个表的查询通过 select 节点配置。
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,⽀持延迟加载的原理都是⼀样的。
Mybatis的一级缓存和二级缓存
1) 一级缓存: 一级缓存是SqlSession级别的缓存,默认开启,其存储作 用域为 Session。
它指的是Mybatis中sqlSession对象的缓存,当我们执行查询以后,查询的结果会同时存入到SqlSession为我们提供的一块区域中,该区域的结构是一个Map,当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,的话直接拿出来用,当SqlSession对象消失时,mybatis的一级缓存也就消失了,同时一级缓存是SqlSession范围的缓存,当调用SqlSession的修改、添加、删除、commit(),close等方法时,就会清空一级缓存。 不同的sqlSession之间的缓存数据区域是互相不影响的。也就是他只能作用在同一个sqlSession中,不同的sqlSession中的缓存是互相不能读取的。
实际开发中,MyBatis通常和Spring进行整合开发。Spring将事务放到Service中管理,对于每一个service中的sqlsession是不同的。所以spring整合之后,如果没有事务,一级缓存是没有意义的。
2) 二级缓存与一级缓存其机制相同,MyBatis的二级缓存是Application(mapper)级别的缓存,多个SqlSession可以共用二级缓存,它可以提高对数据库查询的效率,以提高应用的性能。默认不打开二级缓存,要手动开启二级缓存
他值得是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession共享其缓存,但是其中缓存的是数据而不是对象,所以从二级缓存再次查询出得结果的对象与
第一次存入的对象是不一样的。二级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache, 当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。
使用缓存是为了减少和数据库的交互次数,提高执行效率
什么是Mybatis的接口绑定?有哪些实现方式?
接口绑定,就是在 MyBatis 中任意定义接口,然后把接口里面的方法和 SQL 语句绑定, 我们直接调用接口方法就可以,这样比起原来了 SqlSession 提供的方 法我们可以有更加灵活的选择和设置。
接口绑定有两种实现方式:
- 一种是通过注解绑定,就是在接口的方法上面加 上 @Select.@Update 等注解,里面包含 Sql 语句来绑定;
- 另外一种就是通过 xml 里面写 SQL 来绑定, 在这种情况下,要指定xml 映射文件里面的 namespace 必须为接口的全路径名。当 Sql 语句比较简单时候,用注解绑定, 当 SQL 语句比 较复杂时候,用 xml 绑定,一般用 xml 绑定的比较多。
使用Mybatis的mapper接口调用时有哪些需求?
- Mapper 接口方法名和 mapper.xml 中定义的每个 sql 的 id 相同;
- Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的
- parameterType 的类型相同;
- Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的resultType 的类型相同;
- Mapper.xml 文件中的 namespace 即是 mapper 接口的类路径。
简述Mybatis插件的运行原理,以及如何编写一个插件
插件是对系统默认功能的自定义修改,例如mybatis里面自定义插件,它实现的拦截器的功能。此类插件等同于拦截器。
我们知道,MyBatis有四大核心对象:
(1)ParameterHandler:处理SQL的参数对象
(2)ResultSetHandler:处理SQL的返回结果集
(3)StatementHandler:数据库的处理对象,用于执行SQL语句
(4)Executor:MyBatis的执行器,用于执行增删改查操作
那么,MyBatis拦截器针对的对象就是上面“四大金刚”。在Java里面,我们想拦截某个对象,只需要把这个对象包装一下,用代码行话来说,就是重新生成一个代理对象。一旦我们在mybatis-config.xml里面配置了插件,MyBatis四大核心对象(四大金刚)就会变身,变成代理对象
编写插件:实现 Mybatis 的 Interceptor 接口并复写 intercept()方法,然 后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在 配置文件中配置你编写的插件。