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问题仍然存在,开启懒加载避免。