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/>来自增主键,例:
<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的应该可以很容易看得懂,这部分内容在官网http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html中有详细解释,有了这些动态SQL标签,在编写SQL语句的时候可以非常灵活的自定义SQL语句,下面讲到批量插入的时候会提到<foreach/>标签的使用,这里不过多赘述。
批量操作
当需要批量insert时,如果是insert多少就调用多少次mapper,应该是不合理的,不推荐使用,性能会很低。这时候就需要上面提到的动态SQL来执行批量的SQL操作。
<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。
sqlSessionFactory.openSession(ExecutorType.BATCH);
这种方法我用的不多,不多赘述。
联合查询
上面有提到在联合查询的时候有两种方式,一种是嵌套结果,一种是嵌套查询。
嵌套结果(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):
<!-- 嵌套查询 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对多):
<!-- 嵌套结果 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对多):
<!-- 嵌套查询 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问题仍然存在,开启懒加载避免。