面试必须要看看
1、MyBatis 中的一级缓存和二级缓存是什么?它们的区别是什么?
MyBatis 中的一级缓存是指 SqlSession 对象内部的缓存,它是默认开启的。一级缓存的生命周期是与 SqlSession 对象绑定的,当 SqlSession 关闭时,缓存也会自动清空。一级缓存的作用是减少对数据库的查询次数,提高查询效率。
MyBatis 中的二级缓存是指 SqlSessionFactory 对象内部的缓存,它需要手动开启和配置。二级缓存的生命周期是与 SqlSessionFactory 对象绑定的,当应用程序关闭时,缓存也会自动清空。二级缓存的作用是在多个 SqlSession 之间共享缓存,提高查询效率。二级缓存可以使用 Ehcache、Redis 等第三方缓存框架来实现。
2、MyBatis 中的事务是如何控制的?
MyBatis 中的事务是由 JDBC 控制的。在 Mapper 接口方法中,可以使用 @Transactional 注解来声明事务的范围。MyBatis 支持声明式事务和编程式事务两种方式,可以根据实际需求选择适合的方式来控制事务。
3、MyBatis 中的多数据源是如何实现的?
MyBatis 中的多数据源可以通过配置多个 SqlSessionFactory 对象来实现。在 Mapper 接口中,可以使用 @MapperScan 注解来指定要扫描的 Mapper 接口所在的包,从而将多个数据源与不同的 Mapper 接口关联起来。
4、MyBatis 中的缓存失效是如何处理的?
MyBatis 中的缓存失效可以通过以下几种方式来处理:
手动清除缓存:在 Mapper 接口中,可以使用 @CacheEvict 注解来手动清除缓存。
设置缓存过期时间:可以在映射文件或 Mapper 接口中,设置缓存的过期时间,从而实现缓存的自动失效。
在 SQL 语句中添加 FOR UPDATE 子句:可以在 SQL 语句中添加 FOR UPDATE 子句,从而实现缓存的失效和锁定。
5、MyBatis 中的动态 SQL 是什么?它的作用是什么?
MyBatis 中的动态 SQL 是指根据条件动态生成 SQL 语句的技术。它的作用是可以根据实际条件生成相应的 SQL 语句,从而实现更加灵活的查询操作。MyBatis 中可以使用动态 SQL 来实现 if、choose、when、otherwise、foreach 等语句块。
6、MyBatis 中的 SQL 解析是如何实现的?
MyBatis 中的 SQL 解析是通过 OGNL(Object-Graph Navigation Language)表达式实现的。在映射文件或 Mapper 接口中,可以使用 OGNL 表达式来动态生成 SQL 语句和参数。OGNL 表达式可以访问 Java 对象和集合,以实现复杂的查询操作。
7、MyBatis 中的 TypeHandler 是什么?它的作用是什么?
MyBatis 中的 TypeHandler 是用于实现 Java 类型与 JDBC 类型之间的转换的组件。它的作用是可以自定义数据类型的转换规则,从而实现更加灵活的数据映射。MyBatis 中内置了许多常见的 TypeHandler,同时也可以自定义 TypeHandler。
8、MyBatis 中的注解和 XML 配置文件有什么区别?它们的优缺点是什么?
MyBatis 中的注解和 XML 配置文件都可以用来配置 Mapper 接口和 SQL 语句。它们的区别在于,注解方式是通过 Java 代码来实现配置,而 XML 配置文件是通过 XML 文件来实现配置。注解方式相对于 XML 配置文件来说,更加简洁和方便,但是可读性和可维护性可能会差一些。XML 配置文件相对于注解方式来说,可读性和可维护性更好,但是相对繁琐一些。另外,注解方式不支持动态 SQL,而 XML 配置文件支持动态 SQL。
9、MyBatis 中的 Mapper 接口和 Mapper 映射文件是如何关联的?
在 MyBatis 中,Mapper 接口和 Mapper 映射文件是通过一个相同的命名空间来关联的。在 Mapper 接口中定义的方法名必须与 Mapper 映射文件中定义的语句的 id 属性值相同。同时,Mapper 映射文件中的 namespace 属性值必须与 Mapper 接口的全限定名相同。
10、MyBatis 中的事务是如何控制的?
在 MyBatis 中,事务是通过 SqlSession 来控制的。在默认情况下,MyBatis 中的事务是开启的,且事务的隔离级别为 REPEATABLE READ。如果需要自定义事务的隔离级别,可以在 SqlSessionFactory 中配置事务管理器和数据源,从而实现自定义事务的控制。另外,MyBatis 还提供了 @Transactional 注解来实现事务的控制,通过在方法上添加 @Transactional 注解来指定事务的隔离级别和传播行为。
11、#{}和${}的区别是什么?
${}是字符串替换,#{}是预处理;
Mybatis在处理${}时,就是把这个符号直接替换成变量的值。而Mybatis在处理#{}时,会对sql语句进行预处理,将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
使用#{}可以有效的防止SQL注入,提高系统安全性。
12、Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?
不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;
原因就是namespace+id是作为Map的key使用的,如果没有namespace,就剩下id,那么,id重复会导致数据互相覆盖。有了namespace,自然id就可以重复,namespace不同,namespace+id自然也就不同。
13、Mybatis是如何进行分页的?分页插件的原理是什么?
Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql
14、Mybatis的一级、二级缓存?
MyBatis的缓存分为一级缓存和二级缓存,一级缓存是SqlSession级别的缓存,二级缓存是Mapper级别的缓存。
(1)一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。
(2)二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 ;
(3)对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear 掉并重新更新,如果开启了二级缓存,则只根据配置判断是否刷新。
15、Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
第一种是使用标签,逐一定义数据库列名和对象属性名之间的映射关系。
第二种是使用sql列的别名功能,将列的别名书写为对象属性名。
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
16、使用MyBatis的mapper接口调用时有哪些要求?
Mapper接口方法名和mapper.xml中定义的每个sql的id相同;
Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同;
Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同;
Mapper.xml文件中的namespace即是mapper接口的类路径。
17、请说说MyBatis的工作原理
1、 读取MyBatis配置文件:mybatis-config.xml为MyBatis的全局配置文件,配置了MyBatis的运;行环境等信息,例如数据库连接信息。
2、 加载映射文件映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在;MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。
3、 构造会话工厂:通过MyBatis的环境等配置信息构建会话工厂SqlSessionFactory;
4、 创建会话对象:由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法;
5、 Executor执行器:MyBatis底层定义了一个Executor接口来操作数据库,它将根据SqlSession;传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。
6、 MappedStatement对象:在Executor接口的执行方法中有一个MappedStatement类型的参;数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。
7、 输入参数映射:输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类;型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。
8、 输出结果映射:输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类;型。输出结果映射过程类似于 JDBC 对结果集的解析过程。
18、Mybatis都有哪些Executor执行器?它们之间的区别是什么?
Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map<String, Statement>内,供下一次使用。简言之,就是重复使用Statement对象。
BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
19、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()方法的调用。这就是延迟加载的基本原理。
20、如何获取生成的主键
新增标签中添加:keyProperty=" ID " 即可
<insert id="insert" useGeneratedKeys="true" keyProperty="userId" >
insert into user(user_name, user_password, create_time)
values(#{userName},{userPassword} ,{createTime, jdbcType=TIMESTAMP})
</insert>
int id=mapper.insert(user)
21、简述Mybatis的插件运行原理,以及如何编写一个插件。
Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。
实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。
22、MyBatis的乐观锁是怎么实现的?
MyBatis的乐观锁是通过版本号实现的,即在数据表中增加一个版本号字段。在更新时,比较版本号是否一致,如果一致才更新数据。
@Update("UPDATE user SET name = #{name}, version = #{version + 1} WHERE id = #{id} AND version = #{version}")
int updateUser(User user);
23、 MyBatis中如何处理存储过程?
可以使用select标签调用存储过程,使用resultMap映射输出参数。
<select id="callProcedure" statementType="CALLABLE" parameterType="Map">
{call my_procedure(
#{inputParam, mode=IN, jdbcType=INTEGER},
#{outputParam, mode=OUT, jdbcType=VARCHAR}
)}
</select>
24、MyBatis的懒加载是什么?
懒加载是指在需要使用关联数据时才去加载,而不是在查询主体数据时就将关联数据一并加载。
<resultMap id="userResultMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<collection property="orders" ofType="Order" column="user_id" select="getOrdersByUserId" lazyLoading="true"/>
</resultMap>
25、MyBatis中如何处理返回多个结果集?
通过resultSets属性指定多个结果集。
<select id="getUserAndOrder" resultType="User" statementType="CALLABLE" parameterType="Map" resultSets="user,order">
{call get_user_and_order(#{userId, mode=IN, jdbcType=INTEGER})}
</select>
26、MyBatis中如何实现动态更新?
使用标签可以方便地动态拼接更新字段。
27、MyBatis 是如何处理枚举类型的?
MyBatis 可以通过实现 TypeHandler 接口来处理枚举类型。用户可以创建自定义的 TypeHandler,然后在 MyBatis 配置文件中指定这个自定义的类型处理器来对枚举类进行转换操作。
28、MyBatis 如何实现一对一关联查询?
可以通过联表查询或者嵌套查询来实现一对一映射。在 ResultMap 中使用 association 元素进行配置,确定对象之间的关联关系。
29、MyBatis 如何实现一对多关联查询?
通过在 ResultMap 中配置 collection 元素来实现一对多的映射。这可以根据一方的主键关联到多方的外键来实现。