Mapper.xml配置文件解读

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> Mapper.xml配置文件解读

mapper.xml配置文件解读

①. namespace:与对应mapper接口关联,使其方法与xml定义的标签id相对应。

②. resultType:设置sql语句返回的类型,可以是基本类型,也可以是实体类类型,实体类一般全包名作为参数设置,也可以在mybatis配置文件中设置实体类的别名来设置其resultType。其优点在于简单方便,缺点在于需要创建实体类才能这么用,在于一些多表关联,复杂的结果映射关系中不适用。

③. resultMap:设置sql语句返回的结果集,为自定义映射,在嵌套查询、嵌套结果中使用,可以很方便的对结果集进行配置映射关系,在嵌套查询中甚至不需要写连接语句即可完成关联1对1或1对多查询,底层是做了两次查询,所以嵌套查询存在一个N+1的问题,有时候不需要关联查询但每次都会把关联结果查出来,这就是N+1问题,可以通过在Mybatis配置文件中的settings/标签中开启懒加载,底层原理是用了一个动态代理去代理结果集,当用到或是取出结果集中关联的对象时,才进行第二次查询,否则只进行一次查询。

④. Mybatis提供了CRUD四种查询标签例如select/等来帮助编写SQL语句,几个标签中常用属性如id需要与mapper接口方法名称一致,用来对应namespace中的mapper接口。如resultType、resultMap上面介绍过了。在insert/标签中有useGeneratedKeys属性会自动使用JDBC的getGeneratedKeys方法来取出数据库自增的主键(需要有自增字段),在MySql与SQL Server中可以使用,但在oracle需要创建序列,然后使用selectKey/来自增主键,例:

1234567
  insert id="insert" parameterType="com.demo.Pojo" useGeneratedKeys="true" keyProperty="id"     insert into DEMO (ID, NAME)    values (${id}, #{name})    selectKey keyProperty="id" order="BEFORE" resultType="int"      SELECT SEQ_DEMO_ID.NEXTVAL FROM dual    /selectKey  /insert

insert id=”insert” parameterType=”com.demo.Pojo” useGeneratedKeys=”true” keyProperty=”id”
insert into DEMO (ID, NAME)
values (${id}, #{name})
selectKey keyProperty=”id” order=”BEFORE” resultType=”int”
SELECT SEQ_DEMO_ID.NEXTVAL FROM dual
/selectKey
/insert

⑤. 动态SQL:Mybatis提供动态SQL标签,类似与JSP中的JSTL,有使用过JSP的应该可以很容易看得懂,这部分内容在官网中有详细解释,有了这些动态SQL标签,在编写SQL语句的时候可以非常灵活的自定义SQL语句,下面讲到批量插入的时候会提到foreach/标签的使用,这里不过多赘述。

批量操作

当需要批量insert时,如果是insert多少就调用多少次mapper,应该是不合理的,不推荐使用,性能会很低。这时候就需要上面提到的动态SQL来执行批量的SQL操作。

123456789
  insert id="insertBatch" parameterType="list"    insert into test (id, nums, name    )    values    foreach collection="list" item="item" separator=","    (#{item.id,jdbcType=INTEGER}, #{item.nums,jdbcType=INTEGER}, #{item.name,jdbcType=VARCHAR}    )    /foreach  /insert

insert id=”insertBatch” parameterType=”list”
insert into test (id, nums, name
)
values
foreach collection=”list” item=”item” separator=”,”
(#{item.id,jdbcType=INTEGER}, #{item.nums,jdbcType=INTEGER}, #{item.name,jdbcType=VARCHAR}
)
/foreach
/insert

只需要一条SQL语句即可完成批量的操作,性能最高,但缺点是SQL语句长度有限制,可以判断一下list中的条数来限制一下SQL语句长度。

还有一种方法是在获取SqlSession的时候设置ExecutorType为BATCH。

1
sqlSessionFactory.openSession(ExecutorType.BATCH);

sqlSessionFactory.openSession(ExecutorType.BATCH);

这种方法我用的不多,不多赘述。

联合查询

上面有提到在联合查询的时候有两种方式,一种是嵌套结果,一种是嵌套查询。

嵌套结果(1对1):

12345678910111213141516171819
  !-- 嵌套结果 start  1:1--  resultMap id="blogResultMap2" type="com.dal.resultmap.BlogResultMap"    id column="bid" jdbcType="INTEGER" property="bid" /    result column="name" jdbcType="VARCHAR" property="name" /    association property="author" javaType="com.gupao.dal.dao.Author"      id column="aid" jdbcType="INTEGER" property="aid" /      result column="author_name" jdbcType="VARCHAR" property="authorName" /    /association  /resultMap   select id="selectBlogAuthor2" resultMap="blogResultMap2" parameterType="int"    select    *    from blog b,author a    where bid = #{id,jdbcType=INTEGER}    and    b.author_id = a.aid  /select  !-- 嵌套结果 end  1:1--

!– 嵌套结果 start 1:1–
resultMap id=”blogResultMap2” type=”com.dal.resultmap.BlogResultMap”
id column=”bid” jdbcType=”INTEGER” property=”bid” /
result column=”name” jdbcType=”VARCHAR” property=”name” /
association property=”author” javaType=”com.gupao.dal.dao.Author”
id column=”aid” jdbcType=”INTEGER” property=”aid” /
result column=”author_name” jdbcType=”VARCHAR” property=”authorName” /
/association
/resultMap

select id=”selectBlogAuthor2” resultMap=”blogResultMap2” parameterType=”int”
select
*
from blog b,author a
where bid = #{id,jdbcType=INTEGER}
and
b.author_id = a.aid
/select
!– 嵌套结果 end 1:1–

需要在SQL语句中连接多表查询,在resultMap中映射对应字段即可,1对1都是用association/来对应关系

嵌套查询(1对1):

123456789101112131415
  !-- 嵌套查询 start  1:1--  resultMap id="blogResultMap" type="com.dal.resultmap.BlogResultMap"    id column="bid" jdbcType="INTEGER" property="bid" /    result column="name" jdbcType="VARCHAR" property="name" /    association property="author" column="author_id"                 select="com.gupao.dal.dao.AuthorMapper.selectByPrimaryKey" /  /resultMap   select id="selectBlogAuthor" resultMap="blogResultMap" parameterType="int"    select    include refid="Base_Column_List" /    from blog    where bid = #{id,jdbcType=INTEGER}  /select  !-- 嵌套查询 end --

!– 嵌套查询 start 1:1–
resultMap id=”blogResultMap” type=”com.dal.resultmap.BlogResultMap”
id column=”bid” jdbcType=”INTEGER” property=”bid” /
result column=”name” jdbcType=”VARCHAR” property=”name” /
association property=”author” column=”author_id”
select=”com.gupao.dal.dao.AuthorMapper.selectByPrimaryKey” /
/resultMap

select id=”selectBlogAuthor” resultMap=”blogResultMap” parameterType=”int”
select
include refid=”Base_Column_List” /
from blog
where bid = #{id,jdbcType=INTEGER}
/select
!– 嵌套查询 end –

不需要在SQL语句中写连接语句,正常查询即可,不同于嵌套结果的是在resultMap中的association/里有一个属性select,需要指定mapper接口的方法,其原理就是再去对应的mapper中再做一次查询,将结果封装到类中属性,所以这里会有一个N+1的问题,上面也有提到过,需要开启懒加载避免N+1问题。

嵌套结果(1对多):

12345678910111213141516171819
  !-- 嵌套结果 1:N start  --  resultMap id="blogPostsResultMap2" type="com.dal.resultmap.BlogPostsResultMap"    id column="bid" jdbcType="INTEGER" property="bid" /    result column="name" jdbcType="VARCHAR" property="name" /    result column="author_id" jdbcType="INTEGER" property="authorId" /    collection property="posts" ofType="com.dal.dao.Posts"       id column="pid" jdbcType="INTEGER" property="pid" /      result column="post_name" jdbcType="VARCHAR" property="postName" /    /collection  /resultMap   select id="selectBlogPosts2" resultMap="blogPostsResultMap2" parameterType="int"    select    *    from blog b,posts p    where b.bid = #{id,jdbcType=INTEGER}    and b.bid = p.blog_id  /select  !-- 嵌套结果 1:N end --

!– 嵌套结果 1:N start –
resultMap id=”blogPostsResultMap2” type=”com.dal.resultmap.BlogPostsResultMap”
id column=”bid” jdbcType=”INTEGER” property=”bid” /
result column=”name” jdbcType=”VARCHAR” property=”name” /
result column=”author_id” jdbcType=”INTEGER” property=”authorId” /
collection property=”posts” ofType=”com.dal.dao.Posts”
id column=”pid” jdbcType=”INTEGER” property=”pid” /
result column=”post_name” jdbcType=”VARCHAR” property=”postName” /
/collection
/resultMap

select id=”selectBlogPosts2” resultMap=”blogPostsResultMap2” parameterType=”int”
select
*
from blog b,posts p
where b.bid = #{id,jdbcType=INTEGER}
and b.bid = p.blog_id
/select
!– 嵌套结果 1:N end –

不同于1对1的就是association/标签换成了collection/表示映射多个实体,也就是1对多,嵌套结果都是要在SQL语句中做连接操作,设置对应的映射即可。还有就是collection/标签多了一个属性ofType,可以看作是List存放结果的类型(泛型)。

嵌套查询(1对多):

1234567891011121314151617
  !-- 嵌套查询 1:N start  --  resultMap id="blogPostsResultMap" type="com.dal.resultmap.BlogPostsResultMap"    id column="bid" jdbcType="INTEGER" property="bid" /    result column="name" jdbcType="VARCHAR" property="name" /    result column="author_id" jdbcType="INTEGER" property="authorId" /    collection column="bid" property="posts"                select="selectByBlogId" ofType="com.dal.dao.Posts"     /collection  /resultMap   select id="selectByBlogId" parameterType="java.lang.Integer"                  resultType="com.dal.dao.Posts"    select    pid,post_name as postName,blog_id as blogId    from posts    where blog_id = #{id,jdbcType=INTEGER}  /select

!– 嵌套查询 1:N start –
resultMap id=”blogPostsResultMap” type=”com.dal.resultmap.BlogPostsResultMap”
id column=”bid” jdbcType=”INTEGER” property=”bid” /
result column=”name” jdbcType=”VARCHAR” property=”name” /
result column=”author_id” jdbcType=”INTEGER” property=”authorId” /
collection column=”bid” property=”posts”
select=”selectByBlogId” ofType=”com.dal.dao.Posts”
/collection
/resultMap

select id=”selectByBlogId” parameterType=”java.lang.Integer”
resultType=”com.dal.dao.Posts”
select
pid,post_name as postName,blog_id as blogId
from posts
where blog_id = #{id,jdbcType=INTEGER}
/select

嵌套查询的SQL语句都是不需要写连接语句,都是在resultMap中的collection/或是另一个关联标签中加上一个select属性设置另一个mapper的查询方法,这里的collection/也需要一个ofType(泛型)。这里的N+1问题仍然存在,开启懒加载避免。

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> Mapper.xml配置文件解读


 上一篇
介绍Mybatis与使用(什么是Mybatis?) 介绍Mybatis与使用(什么是Mybatis?)
一、什么是Mybatis?在介绍Mybatis之前,抛出一个问题,什么是Mybatis呢?这里引用Mybatis官网的一段话来介绍什么是Mybatis。 What is MyBatis? 1、MyBatis is a first cla
2021-04-05
下一篇 
MyBatis概览(各组件以及底层实现原理等) MyBatis概览(各组件以及底层实现原理等)
一、MyBatis概览 这是Mybatis的整体架构图,可以看出它是由几个主要组件组成,分别为Configuration、Sql映射、Mapper、MappedStatements组成,Configuration包含了所有启动时的配置信息
2021-04-05