XML 映射文件

  本文参考mybatis中文官网进行学习总结:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html

  MyBatis 的真正强大在于它的映射语句,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 为聚焦于 SQL 而构建,以尽可能地为你减少麻烦。

  SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):

  • cache – 对给定命名空间的缓存配置。
  • cache-ref – 对其他命名空间缓存配置的引用。
  • resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
  • sql – 可被其他语句引用的可重用语句块。
  • insert – 映射插入语句
  • update – 映射更新语句
  • delete – 映射删除语句
  • select – 映射查询语句

select

  查询语句是 MyBatis 中最常用的元素之一,光能把数据存到数据库中价值并不大,只有还能重新取出来才有用,多数应用也都是查询比修改要频繁。对每个插入、更新或删除操作,通常间隔多个查询操作。这是 MyBatis 的基本原则之一,也是将焦点和努力放在查询和结果映射的原因。简单查询的 select 元素是非常简单的。比如:

  1. <resultMap id="BaseResultMap" type="blog">
  2. <id column="bid" property="bid" jdbcType="INTEGER"/>
  3. <result column="name" property="name" jdbcType="VARCHAR"/>
  4. <result column="author_id" property="authorId" jdbcType="INTEGER"/>
  5. </resultMap>
  6. <!--****************************************************************************************-->
  7. <!--简单查询-->
  8. <select id="selectBlogById" resultMap="BaseResultMap" statementType="PREPARED" useCache="false">
  9. select * from blog where bid = #{bid}
  10. </select>

  #{bid} 这就告诉 MyBatis 创建一个预处理语句(PreparedStatement)参数,在 JDBC 中,这样的一个参数在 SQL 中会由一个“?”来标识,并被传递到一个新的预处理语句中,就像这样:

  1. // 近似的 JDBC 代码,非 MyBatis 代码...
  2. String selectBlogById= "SELECT * FROM BLOG WHERE BID=?";
  3. PreparedStatement ps = conn.prepareStatement(selectBlogById);
  4. ps.setInt(,bid);

  当然,使用 JDBC 意味着需要更多的代码来提取结果并将它们映射到对象实例中,而这就是 MyBatis 节省你时间的地方。select 元素允许你配置很多属性来配置每条语句的作用细节。

  1. <select
  2. id="selectPerson"
  3. parameterType="int"
  4. parameterMap="deprecated"
  5. resultType="hashmap"
  6. resultMap="personResultMap"
  7. flushCache="false"
  8. useCache="true"
  9. timeout=""
  10. fetchSize=""
  11. statementType="PREPARED"
  12. resultSetType="FORWARD_ONLY">

  相关属性描述:

属性 描述
id 在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler) 推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap 这是引用外部 parameterMap 的已经被废弃的方法。请使用内联参数映射和 parameterType 属性。
resultType 从这条语句中返回的期望类型的类的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。可以使用 resultType 或 resultMap,但不能同时使用。
resultMap 外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂映射的情形都能迎刃而解。可以使用 resultMap 或 resultType,但不能同时使用。
flushCache 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。
useCache 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。
fetchSize 这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等。 默认值为未设置(unset)(依赖驱动)。
statementType STATEMENT,PREPARED 或 CALLABLE 中的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetType FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖驱动)。
databaseId 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。
resultOrdered 这个设置仅针对嵌套结果 select 语句适用:如果为 true,就是假设包含了嵌套结果集或是分组,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。 这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false
resultSets 这个设置仅对多结果集的情况适用。它将列出语句执行后返回的结果集并给每个结果集一个名称,名称是逗号分隔的。

insert, update 和 delete:

  数据变更语句 insert,update 和 delete 的实现非常接近:

  1. <insert
  2. id="insertAuthor"
  3. parameterType="domain.blog.Author"
  4. flushCache="true"
  5. statementType="PREPARED"
  6. keyProperty=""
  7. keyColumn=""
  8. useGeneratedKeys=""
  9. timeout="">
  10.  
  11. <update
  12. id="updateAuthor"
  13. parameterType="domain.blog.Author"
  14. flushCache="true"
  15. statementType="PREPARED"
  16. timeout="">
  17.  
  18. <delete
  19. id="deleteAuthor"
  20. parameterType="domain.blog.Author"
  21. flushCache="true"
  22. statementType="PREPARED"
  23. timeout="">

  相关属性描述:

属性 描述
id 命名空间中的唯一标识符,可被用来代表这条语句。
parameterType 将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap 这是引用外部 parameterMap 的已经被废弃的方法。请使用内联参数映射和 parameterType 属性。
flushCache 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:true(对于 insert、update 和 delete 语句)。
timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。
statementType STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
useGeneratedKeys (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。
keyProperty (仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认值:未设置(unset)。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望使用多个生成的列,也可以设置为逗号分隔的属性名称列表。
databaseId 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。

下面就是 insert,update 和 delete 语句的示例:

  1. <insert id="insertAuthor">
  2. insert into Author (id,username,password,email,bio)
  3. values (#{id},#{username},#{password},#{email},#{bio})
  4. </insert>
  5.  
  6. <update id="updateAuthor">
  7. update Author set
  8. username = #{username},
  9. password = #{password},
  10. email = #{email},
  11. bio = #{bio}
  12. where id = #{id}
  13. </update>
  14.  
  15. <delete id="deleteAuthor">
  16. delete from Author where id = #{id}
  17. </delete>

  如前所述,插入语句的配置规则更加丰富,在插入语句里面有一些额外的属性和子元素用来处理主键的生成,而且有多种生成方式。首先,如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上就 OK 了。如果你的数据库还支持多行插入, 你也可以传入一个 Blog数组或集合,并返回自动生成的主键。

  1. <!--批量插入-->
  2. <insert id="insertBlogs" useGeneratedKeys="true"
  3. keyProperty="bid">
  4. insert into blog (name, author_id) values
  5. <foreach item="item" collection="list" separator=",">
  6. (#{item.name}, #{item.authorId})
  7. </foreach>
    </insert>

sql

  这个元素可以被用来定义可重用的 SQL 代码段,这些 SQL 代码可以被包含在其他语句中。它可以(在加载的时候)被静态地设置参数。 在不同的包含语句中可以设置不同的值到参数占位符上。mybatis中sql标签与include标签进行配合,灵活的查询需要的数据。

  1. <sql id="ref">
  2. bid,name,authorId
  3. </sql>
  4.  
  5. <select id="selectbyId" resultMap="BaseResultMap">
  6. select
  7. <include refid="ref"/>
  8. from
  9. blog where bid = #{bid}
  10. </select>

  sql标签中id属性对应include标签中的refid属性。通过include标签将sql片段和原sql片段进行拼接成一个完成的sql语句进行执行。include标签中还可以用property标签,用以指定自定义属性。

  1. <select id="selectbyId" resultMap="BaseResultMap">
  2. select
  3. <include refid="ref">
  4. <property name="abc" value="bid"/>
  5. </include>
  6. from
  7. blog where bid = #{bid}
  8. </select>

  此时,可以在sql标签中取出对应设置的自定义属性中的值,例如接上代码例子:

  1. <sql id="ref">
  2. ${abc},name,authorId
  3. </sql>
  4.  
  5. <select id="selectbyId" resultMap="BaseResultMap">
  6. select
  7. <include refid="ref">
  8. <property name="abc" value="bid"/>
  9. </include>
  10. from
  11. blog where bid = #{bid}
  12. </select>

  在sql标签中通过${}取出对应include标签中设置的属性值。

  关联(association)元素处理“有一个”类型的关系。 比如,在我们的示例中,一个博客有一个用户。关联结果映射和其它类型的映射工作方式差不多。 你需要指定目标属性名以及属性的javaType(很多时候 MyBatis 可以自己推断出来),在必要的情况下你还可以设置 JDBC 类型,如果你想覆盖获取结果值的过程,还可以设置类型处理器。关联的不同之处是,你需要告诉 MyBatis 如何加载关联。MyBatis 有两种不同的方式加载关联:

  • 嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。
  • 嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。

关联的嵌套 Select 查询

  1. <!-- 另一种联合查询(一对一)的实现,但是这种方式有“N+”的问题 -->
  2. <resultMap id="BlogWithAuthorQueryMap" type="com.wuzz.demo.associate.BlogAndAuthor">
  3. <id column="bid" property="bid" jdbcType="INTEGER"/>
  4. <result column="name" property="name" jdbcType="VARCHAR"/>
  5. <association property="author" javaType="com.wuzz.demo.entity.Author"
  6. column="author_id" select="selectAuthor"/>
  7. </resultMap>
  8.  
  9. <!-- 嵌套查询 -->
  10. <select id="selectAuthor" parameterType="int" resultType="com.wuzz.demo.entity.Author">
  11. select author_id authorId, author_name authorName
  12. from author where author_id = #{authorId}
  13. </select>
  14.  
  15. <!-- 根据文章查询作者,一对一,嵌套查询,存在N+1问题,可通过开启延迟加载解决 -->
  16. <select id="selectBlogWithAuthorQuery" resultMap="BlogWithAuthorQueryMap" >
  17. select b.bid, b.name, b.author_id, a.author_id , a.author_name
  18. from blog b
  19. left join author a
  20. on b.author_id=a.author_id
  21. where b.bid = #{bid, jdbcType=INTEGER}
  22. </select>

  就是这么简单。我们有两个 select 查询语句:一个用来加载博客(Blog),另外一个用来加载作者(Author),而且博客的结果映射描述了应该使用 selectAuthor 语句加载它的 author 属性。其它所有的属性将会被自动加载,只要它们的列名和属性名相匹配。这种方式虽然很简单,但在大型数据集或大型数据表上表现不佳。这个问题被称为“N+1 查询问题”。 概括地讲,N+1 查询问题是这样子的:

  • 你执行了一个单独的 SQL 语句来获取结果的一个列表(就是“+1”)。
  • 对列表返回的每条记录,你执行一个 select 查询语句来为每条记录加载详细信息(就是“N”)。

  这个问题会导致成百上千的 SQL 语句被执行。有时候,我们不希望产生这样的后果。MyBatis 能够对这样的查询进行延迟加载,因此可以将大量语句同时运行的开销分散开来。mybatis.configuration.lazy-loading-enabled=true 可以开启延时加载 mybatis.configuration.aggressive-lazy-loading=true 可以指定哪些方法调用查询, 然而,如果你加载记录列表之后立刻就遍历列表以获取嵌套的数据,就会触发所有的延迟加载查询,性能可能会变得很糟糕。所以还有另外一种方法。

关联的嵌套结果映射

  1. <!-- 根据文章查询作者,一对一查询的结果,嵌套查询 -->
  2. <resultMap id="BlogWithAuthorResultMap" type="com.wuzz.demo.associate.BlogAndAuthor">
  3. <id column="bid" property="bid" jdbcType="INTEGER"/>
  4. <result column="name" property="name" jdbcType="VARCHAR"/>
  5. <!-- 联合查询,将author的属性映射到ResultMap -->
  6. <association property="author" javaType="com.wuzz.demo.entity.Author">
  7. <id column="author_id" property="authorId"/>
  8. <result column="author_name" property="authorName"/>
  9. </association>
  10. </resultMap>
  11. <!-- 根据文章查询作者,一对一,嵌套结果,无N+1问题 -->
  12. <select id="selectBlogWithAuthorResult" resultMap="BlogWithAuthorResultMap" >
  13. select b.bid, b.name, b.author_id, a.author_id , a.author_name
  14. from blog b,author a
  15. where b.author_id=a.author_id and b.bid = #{bid, jdbcType=INTEGER}
  16. </select>

  查询文章带评论的结果(一对多)映射:

  1. <!-- 查询文章带评论的结果(一对多) -->
  2. <resultMap id="BlogWithCommentMap" type="com.wuzz.demo.associate.BlogAndComment" extends="BaseResultMap" >
  3. <collection property="comment" ofType="com.wuzz.demo.entity.Comment">
  4. <id column="comment_id" property="commentId" />
  5. <result column="content" property="content" />
  6. <result column="bid" property="bid" />
  7. </collection>
  8. </resultMap>
  9. <!-- 根据文章查询评论,一对多 -->
  10. <select id="selectBlogWithCommentById" resultMap="BlogWithCommentMap" >
  11. select b.bid, b.name, b.author_id , c.comment_id , c.content,c.bid
  12. from blog b, comment c
  13. where b.bid = c.bid
  14. and b.bid = #{bid}
  15. </select>

  按作者查询文章评论的结果(多对多):

  1. <!-- 按作者查询文章评论的结果(多对多) -->
  2. <resultMap id="AuthorWithBlogMap" type="com.wuzz.demo.associate.AuthorAndBlog" >
  3. <id column="author_id" property="authorId" jdbcType="INTEGER"/>
  4. <result column="author_name" property="authorName" jdbcType="VARCHAR"/>
  5. <collection property="blog" ofType="com.wuzz.demo.associate.BlogAndComment">
  6. <id column="bid" property="bid" />
  7. <result column="name" property="name" />
  8. <result column="author_id" property="authorId" />
  9. <collection property="comment" ofType="com.wuzz.demo.entity.Comment">
  10. <id column="comment_id" property="commentId" />
  11. <result column="content" property="content" />
  12. <result column="bid" property="bid" />
  13. </collection>
  14. </collection>
  15. </resultMap>
  16.  
  17. <!-- 根据作者文章评论,多对多 -->
  18. <select id="selectAuthorWithBlog" resultMap="AuthorWithBlogMap" >
  19. select b.bid, b.name, a.author_id , a.author_name , c.comment_id , c.content,c.bid
  20. from blog b, author a, comment c
  21. where b.author_id = a.author_id and b.bid = c.bid
  22. </select>

动态 SQL

  MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。

  1. if
  2. choose (when, otherwise)
  3. trim (where, set)
  4. foreach

  其中  choose再实际开发中应用的较少,我们这里就其他3个标签进行测试

  1. <!--动态sql-->
  2. <select id="selectBlogById2" resultMap="BaseResultMap" statementType="PREPARED" useCache="false"
  3. parameterType="blog">
  4. select * from blog
  5. <trim prefix="WHERE" prefixOverrides="AND |OR ">
  6. <if test="bid != null and bid !='' ">
  7. bid = #{bid}
  8. </if>
  9. <if test="name != null and name !='' ">
  10. AND name = #{name}
  11. </if>
  12. <if test="authorId != null and authorId != ''">
  13. AND author_id = #{author_id}
  14. </if>
  15. </trim>
  16. </select>

   foreach:动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:

  1. <select id="selectPostIn" resultType="domain.blog.Post">
  2. SELECT *
  3. FROM POST P
  4. WHERE ID in
  5. <foreach item="item" index="index" collection="list"
  6. open="(" separator="," close=")">
  7. #{item}
  8. </foreach>
  9. </select>

mybatis配置mapper.xml 的基本操作的更多相关文章

  1. springboot 配置mybatis 配置mapper.xml

    # 插件 进行配置 也可以用yml # 1. 配置 Tomcat 修改端口号 server.port=8848 server.context-path=/zxf #2.配置数据源 spring.dat ...

  2. mybatis(三)配置mapper.xml 的基本操作

    参考:https://www.cnblogs.com/wuzhenzhao/p/11101555.html XML 映射文件 本文参考mybatis中文官网进行学习总结:http://www.myba ...

  3. (转)解决mybatis的mapper.xml查询不出数据,结果一直为null问题

    背景:记录mybatis使用过程中遇到的相关问题. 解决mybatis的mapper.xml查询不出数据,结果一直为null问题 解决方案: 1 修改实体类与数据库字段名相同 2 修改sql查询语句, ...

  4. mybatis进行mapper.xml测试的时候发生"必须为元素类型 “mapper” 声明属性 “namespace”

    1.Caused by Caused by: org.xml.sax.SAXParseException; lineNumber: 7; columnNumber: 45; 必须为元素类型 " ...

  5. Mybatis学习--Mapper.xml映射文件

    简介 Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心. 映射文件中有很多属性,常用的就是parameterType(输入类型 ...

  6. 【MyBatis】Mapper XML 文件

    Mapper XML文件 MyBatis 的真正强大在于它的映射语句,也是它的魔力所在.由于它的异常强大,映射器的 XML 文件就显得相对简单.如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立 ...

  7. MyBatis - 3.Mapper XML映射文件

    SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序): cache – 给定命名空间的缓存配置. cache-ref – 其他命名空间缓存配置的引用. resultMap – 是最复杂也是 ...

  8. mybatis之mapper.xml分析

    select: id:方法名,在同一个mapper.xml中,要保持唯一 parameterType:指定输入的参数类型,不是必须的,如果不指定,mybatis会自动识别(推荐指定). resultT ...

  9. MAVEN项目不扫描mybatis的mapper.xml问题

    在使用maven+mybatis+spring在开发的时候,遇到问题,总是找不到mapper.xml文件里定义的方法.检查后发现maven编译后并没有将xml文件打包到输出路径,导致bean创建失败. ...

随机推荐

  1. Composer简介与下载安装

    简介: 初次接触Composer的PHP程序员可能是需要下载ThinkPHP框架(5.1),那么什么是Composer,怎么下载安装呢? Composer是一个依赖管理工具,下载管理第三方包是其主要功 ...

  2. jquery 点击加载更多

    html部分 <ul class="bill moreadd"> <div class="total"><span>-< ...

  3. python连接mariadb报错解决1045, "Access denied for user 'root'@'192.168.0.50' (using password: YES)

    [root@localhost ~]# python Python 2.7.5 (default, Apr 11 2018, 07:36:10) [GCC 4.8.5 20150623 (Red Ha ...

  4. liunx-centos-基础命令详解(1) -主要内容来自 —https://www.cnblogs.com/caozy/p/9261224.html

    关机:halt/poweroff :立刻关机reboot :立刻重启 shutdown -r now :立刻重启shutdown -h 00:00 :定时重启 now:立刻shutdown -h +n ...

  5. JS window对象 返回前一个浏览的页面 back()方法

    JS window对象 返回前一个浏览的页面 back()方法,加载 history 列表中的前一个 URL. 语法: window.history.back();   返回前一个浏览的页面 back ...

  6. 前端每日实战:35# 视频演示如何把 CSS 径向渐变用得出神入化,只用一个 DOM 元素就能画出国宝熊猫

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/odKrpy 可交互视频教程 此视频 ...

  7. hdu 6127 : Hard challenge (2017 多校第七场 1008)(计算几何)

    题目链接 题意:二维平面上有n个点(没有重叠,都不在原点,任意两点连线不过原点),每个点有一个权值,用一条过原点的直线把他们划分成两部分,使两部分的权值和的乘积最大.输出最大的乘积. 极角排序后,将原 ...

  8. 对Asycn/Await的研究

    1.async 函数就是 Generator 函数的语法糖. 例如: var fs = require('fs'); var readFile = function (fileName){ retur ...

  9. 1349 - View's SELECT contains a subquery in the FROM clause

    mysql创建视图 报错1349 - View's SELECT contains a subquery in the FROM clause:: 原因创建视图的sql语句中有不支持子查询, 所以需要 ...

  10. 【テンプレート】RMQ

    1174 区间中最大的数 基准时间限制:1 秒 空间限制:131072 KB   收藏  关注 给出一个有N个数的序列,编号0 - N - 1.进行Q次查询,查询编号i至j的所有数中,最大的数是多少. ...