主要参考以下资料并加入一些平时学习时的问题做整理!!! 如果版权问题,立刻删除!
新版Java面试专题视频教程,java八股文面试全套真题+深度详解(含大厂高频面试真题)_哔哩哔哩_bilibili
Mybatis
1、什么是Mybatis?
- MyBatis是一款基于Java的持久层框架,它提供了一种简单的方式来映射数据库操作到Java对象。它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态SQL,可以严格控制SQL执行性能,灵活度高。
- MyBatis可以使用XML或注解来配置映射原生信息,将POJO映射成数据库中的记录,避免了几乎所有JDBC代码和手动设置参数以获取结果集
- 通过XML文件或注解的方式将要执行的各种statement配置起来,并通过Java对象和statement中的SQL的动态参数进行映射生成最终执行的SQL语句,最后由MyBatis框架执行SQL并将结果映射为Java对象并返回
2、说说MyBatis的优点和缺点?
- 优点
- 基于SQL语句编程,相当灵活,不会对应用程序或数据库的现有设计造成任何影响,SQL写在XML里,解除SQL与程序代码的耦合(用注解写就另说了),便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。
- 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接
- 提供应设标签,支持对象与数据库的ORM字段关系映射,提供对象关系映射标签,支持对象关系组件维护
- 缺点
- SQL语句编写的工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求
- SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库
- XML配置较为繁琐,MyBatis的配置文件中需要编写大量的XML代码来描述SQL语句和映射关系,这可能会使配置文件显得较为繁琐
3、#{}
和${}
的区别是什么?
#{}
在SQL语句中表示一个占位符,它可以防止SQL注入攻击,并且可以自动进行参数类型转换。在执行SQL语句时,MyBatis会将参数值以安全的方式设置到SQL语句中。底层使用的是PreparedStatement
,#{}
占位符替换为?
。${}
在SQL语句中也表示一个占位符,但它不会对参数进行任何处理,直接将参数值拼接到SQL语句中,因此容易引发SQL注入攻击。底层使用的是Statement
4、MyBatis执行流程是什么样子的?
- ①读取MyBatis配置文件:mybatis-config.xml加载运行环境和映射文件
- ②构造会话工厂SqlSessionFactory,一个项目只需要一个,单例的,一般由 spring进行管理
- ③会话工厂创建SqlSession对象,这里面就含了执行SQL语句的所有方法
- ④操作数据库的接口,Executor执行器,同时负责查询缓存的维护
- ⑤Executor接口的执行方法中有一个MappedStatement类型的参数,封装了 映射信息
- ⑥输入参数映射
- ⑦输出结果映射
5、Mybatis是否支持延迟加载?延迟加载的底层原理知道吗?
-
支持,在Mybatis配置文件中,可以配置是否启用延迟加载
lazyLoadingEnabled=true|false
,默认是关闭的或者在mapper文件中设置fetch_type=lazy
-
延迟加载在底层主要使用的CGLIB动态代理完成的
- 使用CGLIB创建目标对象的代理对象,这里的目标对象就是开启了 延迟加载的mapper
- 当调用目标方法时(获取另一个实体对象),进入拦截器invoke方法,发现目标方法是null 值,再执行sql查询(懒加载)
- 获取数据以后,调用set方法设置属性值,再继续查询目标方法,就 有值了
6、Mybatis的一级、二级缓存用过吗?
-
mybatis的一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,SqlSession级别,**默认开启。**同一个SqlSession内部的多次查询操作,如果查询的参数和查询语句都相同,那么第一次查询时查询结果会被缓存到一级缓存中,后续的查询操作会直接从缓存中获取结果,而不会再去查询数据库。一级缓存的生命周期与SqlSession的生命周期相同,当SqlSession被关闭时,一级缓存也会被清空。
-
二级缓存是基于namespace和mapper的作用域起作用的,不是依赖于SQL session,默认也是采用 PerpetualCache,HashMap 存储。**因此当多个SqlSession操作同一个Mapper时,他们之间共享一个二级缓存。二级缓存需要单独开启,二级缓存的缓存时间是无限制的,但是它的缓存策略是基于LRU(最近最少使用)算法的。**为了提高缓存命中率,MyBatis还提供了缓存清空机制,可以通过在Mapper中配置
flushCache="true"
来清空缓存。此外,MyBatis还支持基于注解的缓存配置,可以通过在Mapper接口或方法上添加@CacheNamespace
或者@CacheNamespaceRef
注解来配置缓存-
1,全局配置文件
<settings> <setting name="cacheEnabled" value="true> </settings>
-
2,映射文件
使用
<cache/>
标签让当前mapper生效二级缓存
-
-
二级缓存的注意事项
- 1,对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了新增、修改、删除操作后,默认该作用域下所有 select 中的缓存将被 clear。
- 2,二级缓存需要缓存的数据实现Serializable接口。
- 3,只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中。
7、插入数据后如何获取插入数据库数据的主键?
- 在Mapper 接口中的方法上添加一个
@Options
注解,并在注解中指定属性useGeneratedKeys=true
和keyProperty="实体类属性名"
- Mybatis Plus: 自动将主键值回写到实体类中
8、如何处理Java实体类属性名和数据库表中的字段名不一致的情况?
-
如果实体类属性名和数据库表查询返回的字段名不一致,Mybatis不能自动封装,将会导致这些字段的值为null。
-
解决方法如下:
- 在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样
@Select("select id, username, password, name, gender, image, job, entrydate, " + "dept_id AS deptId, create_time AS createTime, update_time AS updateTime " + "from emp " + "