文章目录
- mybatis内部实现过程
- mybatis延迟加载
- 请说说MyBatis的工作原理
- mybatis接口里的方法,参数不同时能重载吗
- mybatis分页插件的原理是什么?
- mybatis的一级、二级缓存👍
- mybatis如何实现多表查询
- mybatis如何实现批量插入👍
- mybatis动态SQL标签有哪些👍
- Mybatis和MybatisPlus有什么区别
- 什么是ORM框架 ,你了解的ORM框架有哪些 ?
更多相关内容可查看
mybatis内部实现过程
加载账套 ,然后通过创建SqlSessionFactory,获取SqlSession对象,通过mapper接口代理,动态加载账套类别等
根据账套信息动态选择环境
public User getUserByIdAndAccount(String accountId, int userId) {
String environmentId = determineEnvironmentId(accountId);
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(environmentId);
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
return userMapper.getUserById(userId);}}
mybatis延迟加载
延迟加载通常用于加载关联的对象或集合,以避免在检索主对象时立即检索其关联对象,特别是当关联对象的数量很大时。延迟加载允许在需要时按需加载关联对象,而不是在查询主对象时就全部加载。
在MyBatis中,可以通过以下两种方式实现延迟加载:
- select标签的fetchType属性:
- 在MyBatis的映射文件中,可以使用fetchType属性来指定关联对象或集合的加载方式。
- 可以设置fetchType属性为lazy,表示延迟加载;设置为eager表示立即加载(默认值)。
xml<select id="selectBlog" resultType="Blog" fetchType="lazy">
select * from blog where id = #{id}
</select>
请说说MyBatis的工作原理
- 加载mybatis核心配置文件
mybatis-config.xml
’ - 加载mybatis映射配置文件
XxxMapper.xml
, 映射配置文件里面就是定义好的SQL语句 - 创建会话工厂对象
SqlSesssionFactory
- 使用会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法
- 根据 SqlSession 传递的参数调用Executor执行器动态地生成需要执行的 SQL 语句
- Executor执行器使用
MappedStatement
完成对请求参数映射 , 底层使用preparedStatement
完成对SQL语句的预编译 , 封装参数 - Executor执行器执行SQL获取ResultSet结果集 , 根据接口所定义的返回类型底层使用反射完成结果集封装 , 返回查询结果
mybatis接口里的方法,参数不同时能重载吗
mybatis接口里的方法,是不能重载的,因为mybatis在执行的时候 , 是通过接口的全限定类名 + 方法名定位要执行的Statement , 如果进行重载就会出现冲突
mybatis分页插件的原理是什么?
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数
举例:select * from student,拦截sql后重写为:select t.* from (select * from student) t limit 0, 10
插件的本质是一个Interceptor 拦截器 , 可以在mybatis在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) : SQL执行
- ParameterHandler (getParameterObject, setParameters) : 参数设置
- ResultSetHandler (handleResultSets, handleOutputParameters) : 结果集封装
- StatementHandler (prepare, parameterize, batch, update, query) : SQL语句预编译
myabtis分页插件的底层就是一个自定义的PageInterceptor
, 拦截查询语句的执行 , 在SQL语句后面自动拼接分页参数
mybatis的一级、二级缓存👍
一级缓存是 SqlSession 级别的缓存。在操作数据库时需要构造 SqlSession 对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的是 SqlSession 之间的缓存数据区(HashMap)是互相不影响
二级缓存是 Mapper 级别的缓存,多个 SqlSession 去操作同一个 Mapper 的 sql 语句,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的
需要注意的是 :
mybatis中一级缓存默认开启 , 二级缓存需要使用配置开启 , 设置cacheEnabled=true
开启二级缓存
- 当SqlSession执行查询时,如果查询语句开启了二级缓存并且缓存中有对应数据,则直接从缓存中获取数据,不再访问数据库。
- 如果缓存中没有对应数据,则SqlSession会去数据库执行查询,并将结果放入缓存。
- 当SqlSession执行更新、插入或删除操作时,会清空相关的二级缓存,以保持数据的一致性。
mybatis如何实现多表查询
mybatis中实现多表查询的方案常见的有两种 :
第一种方式 : 编写多表语句查询多表数据 , 使用<ResultMap>
标签中的association
和collection
标签做一对一和一对多结果集映
例如 : 查询用户信息以及用户的账户信息
<!--定义结果集映射-->
<resultMap id="UserAccountMap" type="User">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!--
配置一对多映射,一个用户可以有多个账户
-->
<collection property="accounts" ofType="Account" >
<id column="aid" property="id"></id>
<result column="id" property="uid"></result>
<result column="money" property="money"></result>
</collection>
</resultMap>
<!--定义查询的sql语句-->
<select id="findAllWithAccount" resultMap="UserAccountMap" >
select u.*,a.id aid,a.MONEY from user u inner join account a on u.id = a.uid
</select>
第二种方式 : 编写多条查询语句, 分别查询多张表的数据 , 使用使用<ResultMap>
标签中的association
和collection
标签做一对一和一对多结果集映
例如 : 查询账户信息, 以及账户所属的用户信息
<!-- 建立对应关系 -->
<resultMap type="account" id="AccountUserMap">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/> <!-- 它是用于指定从表方的引用实体属性的 -->
<association property="user" javaType="user" select="com.itheima.dao.UserDao.findById"
column="uid">
</association>
</resultMap>
<!--定义SQL语句-->
<select id="findAll" resultMap="AccountUserMap">
select * from account
</select>
<!--定义查询的sql语句-->
<select id="findById" resultMap="User" parameterType="int" >
select * from user where id = #{id }
</select>
mybatis如何实现批量插入👍
Mybatis批量插入的方式有三种 :
- 普通插入 : 遍历insert语句,单条执行,效率低下
- 使用
foreach
插入 : 使用foreach
标签将多条数据拼接到一条SQL语句中 , 一次性插入到数据库
<insert id="batchInsert" parameterType="java.util.List">
insert into table1 (field1, field2) values
<foreach collection="list" item="t" index="index" separator=",">
(#{t.field1}, #{t.field2})
</foreach>
</insert>
需要注意的是 :
当插入数量很多时,不能一次性全放在一条语句里 , 之前测试过当表的列数较多(20+)以及一次性插入的行数较多(5000+)时,整个插入的耗时十分漫长,达到了14分钟
原因是因为当拼接的数据比较多 , SQL中存在大量的占位符需要解析 , 对于占位符的解析和参数设置需要消耗大量的时间
如果非要使用 foreach 的方式来进行批量插入的话,可以考虑减少一条 insert 语句中 values 的个数 , 一般按经验来说,一次性插20~50行数量是比较合适的
此外Mysql 对执行的SQL语句大小进行限制,默认允许最大SQL是 4M , SQL大小超过4M会报错
- 使用ExecutorType.BATCH插入
mybatis内置的ExecutorType有3种,SIMPLE、REUSE、BATCH; 默认的是simple,这个模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql;而batch模式重复使用已经预处理的语句,并且批量执行所有更新语句,batch性能更好一些 , 配置方式 :
mybatis:
configuration:
default-executor-type: batch # 开启批处理模式
需要注意的是 : 进行jdbc批处理时需在JDBC的url中加入rewriteBatchedStatements=true
同时batch模式也有自己的问题,比如在Insert操作时,在事务没有提交之前,是没有办法获取到自增的id的
建议有大批量数据需要插入的情况下使用BATCH
模式 , 效率最高
mybatis动态SQL标签有哪些👍
- 基本的增删改查标签 , 例如 :
<insert>
,<select>
,<update>
,<delete>
- 语义处理标签 , 例如 :
where
,set
- 进行条件判断的标签 , 例如 :
<if test="条件">
,<choose> .... <when>...<otherwise>
<!-- if标签 : 条件判断 -->
<select id="selectByUsername" resultType="User">
SELECT * FROM t_user WHERE 1 = 1
<if test="status != null">
AND status = #{status}
</if>
<if test="username != null and username != ''">
AND username = #{username}
</if>
</select>
<!--<choose> .... <when>...<otherwise> 标签, 类似与 : switch 语句 -->
<select id="selectByUsername" resultType="User">
SELECT * FROM t_user WHERE 1 = 1
<choose>
<when test="status != null">
AND status = #{status}
</when>
<otherwise>
AND username = #{username}
</otherwise>
</choose>
</select>
- 遍历循环标签 , 例如 :
<foreach collection="遍历的集合" item="遍历每一项" index="索引" open="遍历开始字符" close="遍历结束字符" separator="遍历分割符号" >
<select id="selectInIdList" resultType="User">
SELECT * FROM t_user
<foreach item="item" index="index" collection="idList" open="id IN (" separator="," close=")" nullable="true">
#{item}
</foreach>
</select>
<script>
标签 : 可以在注解中使用动态SQL
public interface UserSqlMapper {
@Select("<script>" +
"SELECT * FROM t_user" +
"<where>" +
" <if test='status != null'>AND status = #{status}</if>" +
" <if test='username != null'>AND username = #{username}</if>" +
"</where>" +
"</script>")
List<User> selectByUser(User user);
}
<sql>
标签 : 定义SQL片段 , 可以使用include
进行引入, 实现SQL复用
<!--定义SQL片段-->
<sql id="userColumns"> id,username,password </sql>
<select id="selectUsers" resultType="map">
select
<!--引用SQL片段-->
<include refid="userColumns"></include>
from user
</select>
Mybatis和MybatisPlus有什么区别
Mybatis是一个基于XML配置文件和SQL语句的ORM框架。它提供了基本的SQL映射、缓存管理等持久化功能 , Mybatis Plus在Mybatis的基础上进行了扩展,提供了更多功能特性,如分页插件、代码生成器、注解支持 , 多数据源插件等
Mybatis在进行数据持久化时需要编写大量的XML配置文件和SQL语句 , Mybatis Plus则使用注解和API的方式进行数据持久化,使得编码更加便捷和简洁
Mybatis Plus在功能扩展的同时也对性能进行了优化,提供了高效的SQL语句构建和执行能力,并支持动态SQL语句生成,从而提高了应用的性能和效率。
总的来说,Mybatis Plus就是一个Mybatis的增强工具提供了更加强大的功能扩展 , 在使用Mybatis Plus
的同时也可以使用Mybatis中所提供的一些功能 , 完全没有影响
什么是ORM框架 ,你了解的ORM框架有哪些 ?
ORM又叫对象关系映射 , 建立实体对象和数据库表之间的映射关系。开发者操作对象就相当于操作数据库 , 自动生成相关的SQL语句实现对数据库的操作
常见ORM框架:
- Hibernate(Nhibernate):Hibernate是最早的Java ORM框架之一,支持将对象映射到关系数据库中。提供了自动映射、事务管理、连接管理等功能。
- MyBatis:MyBatis提供了更加灵活的SQL语句编写方式,支持动态SQL语句生成和参数绑定等功能。是一个半自动化的ORM框架。
- Mybatis Plus:Mybatis Plus是在MyBatis的基础上扩展而来的ORM框架,它提供了更多的功能特性,如分页插件、代码生成器、注解支持等。
- JPA(Java Persistence API):JPA提供了一种统一的持久化操作方式。许多ORM框架都实现了JPA规范,如Hibernate