MyBatis真正的力量是在映射语句中。这里是奇迹发生的地方。对于所有的力量,SQL映射的XML文件是相当的简单。当然如果你将它们和对等功能的JDBC代码来比较,你会发现映射文件节省了大约95%的代码量。MyBatis的构建就是聚焦于SQL的,使其远离于普通的方式。

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

  • cache - 配置给定命名空间的缓存。
  • cache-ref – 从其他命名空间引用缓存配置。
  • resultMap – 最复杂,也是最有力量的元素,用来描述如何从数据库结果集中来加载你的对象。
  • parameterMap – 已经被废弃了!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除。这里不会记录。
  • sql – 可以重用的SQL块,也可以被其他语句引用。
  • insert – 映射插入语句
  • update – 映射更新语句
  • delete – 映射删除语句
  • select – 映射查询语句

下一部分将从语句本身开始来描述每个元素的细节。

select

  查询语句是使用MyBatis时最常用的元素之一。直到你从数据库取出数据时才会发现将数据存在数据库中是多么的有价值,所以许多应用程序查询要比更改数据多的多。对于每次插入,更新或删除,那也会有很多的查询。这是MyBatis的一个基本原则,也是将重心和努力放到查询和结果映射的原因。对简单类别的查询元素是非常简单的。比如:

<select id=”selectPerson” parameterType=”int” resultType=”hashmap”>
  SELECT * FROM PERSON WHERE ID = #{id}
</select>

  这个语句被称作selectPerson,使用一个int (或Integer)类型的参数,并返回一个HashMap类型的对象,其中的键是列名,值是列对应的值。
  注意参数注释:

#{id}

  这就告诉MyBatis创建一个预处理语句参数。使用JDBC,这样的一个参数在SQL中会由一个“?”来标识,并被传递到一个新的预处理语句中,就像这样:

// Similar JDBC code, NOT MyBatis…
String selectPerson = “SELECT * FROM PERSON WHERE ID=?”;
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id)

  当然,这需要很多单独的JDBC的代码来提取结果并将它们映射到对象实例中,这就是MyBatis节省你时间的地方。我们需要深入了解参数和结果映射。那些细节部分我们下面来了解。

  select元素有很多属性允许你配置,来决定每条语句的作用细节。

<select
id=”selectPerson”
parameterType=”int”
parameterMap=”deprecated”
resultType=”hashmap”
resultMap=”personResultMap”
flushCache=”false”
useCache=”true”
timeout=”10000”
fetchSize=”256”
statementType=”PREPARED”
resultSetType=”FORWARD_ONLY”
>

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. useGeneratedKeys=""
  8. timeout="20000">
  9.  
  10. <update
  11. id="insertAuthor"
  12. parameterType="domain.blog.Author"
  13. flushCache="true"
  14. statementType="PREPARED"
  15. timeout="20000">
  16.  
  17. <delete
  18. id="insertAuthor"
  19. parameterType="domain.blog.Author"
  20. flushCache="true"
  21. statementType="PREPARED"
  22. timeout="20000">

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

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

  如前所述,插入语句有一点多,它有一些属性和子元素用来处理主键的生成。
  首先,如果你的数据库支持自动生成主键的字段(比如MySQL和SQL Server),那么你可以设置useGeneratedKeys=”true”,而且设置keyProperty到你已经做好的目标属性上。例如,如果上面的Author表已经对id 使用了自动生成的列类型,那么语句可以修改为:

  1. <insert i d="insertAuthor" parame terType ="domain.bl og.Author" useGeneratedKeys=”true” keyProperty=”id”>
  2. insert into Author (username,password,email,bio)
  3. values (#{username},#{password},#{email},#{bio})
  4. </insert>

MyBatis有另外一种方法来处理数据库不支持自动生成类型,或者可能JDBC驱动不支持自动生成主键时的主键生成问题。

这里有一个简单(甚至很傻)的示例,它可以生成一个随机ID(可能你不会这么做,但是这展示了MyBatis处理问题的灵活性,因为它并不真的关心ID的生成):

<insert i d="insertAuthor" parame terType ="domain.bl og.Author">
<selectKe y keyPr operty="i d" resultType="int" or der="B EFORE">
  select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
</selectKey>
  insert into Author
  (id, username, password, email,bio, favourite_section)
  values
  (#{id}, #{username}, #{password}, #{email}, #{bio},
  #{favouriteSection,jdbcType=VARCHAR} )
</insert>

在上面的示例中,selectKey元素将会首先运行,Author的id 会被设置,然后插入语句会被调用。这给你了一个简单的行为在你的数据库中来处理自动生成的主键,而不需要使你的Java代码变得复杂。

selectKey元素描述如下:
<selectKey
  keyProperty="id"
  resultType="int"
  order="BEFORE"
  statementType="PREPARED">

sql

这个元素可以被用来定义可重用的SQL代码段,可以包含在其他语句中。比如:
<sql id=”userColumns”> id,username,password </sql>
这个SQL片段可以被包含在其他语句中,例如:
<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>
  select <include refid=”userColumns”/>
  from some_table
  where id = #{id}
</select>

Parameters

  在之前的语句中,你已经看到了一些简单参数的示例。在MyBatis中参数是非常强大的元素。对于简单的做法,大概90%的情况,是不用太多的,比如:
<select id=”selectUsers” parameterType=”int” resultType=”User”>
  select id, username, password
  from users
  where id = #{id}
</select>
  上面的这个示例说明了一个非常简单的命名参数映射。参数类型被设置为“int”,因此这个参数可以被设置成任何内容。原生的类型或简单数据类型,比如整型和没有相关属性的字符串,因此它会完全用参数来替代。然而,如果你传递了一个复杂的对象,那么MyBatis的处理方式就会有一点不同。比如:
<insert id=”insertUser” parameterType=”User” >
  insert into users (id, username, password)
  values (#{id}, #{username}, #{password})
</insert>
  如果User类型的参数对象传递到了语句中,id、username和password属性将会被查找,然后它们的值就被传递到预处理语句的参数中。
  这点对于传递参数到语句中非常好。但是对于参数映射也有一些其他的特性。
  首先,像MyBatis的其他部分,参数可以指定一个确定的数据类型。
#{property,javaType=int,jdbcType=NUMERIC}
  像MyBatis的剩余部分,javaType 通常可以从参数对象中来去顶,除非对象是一个HashMap。那么javaType 应该被确定来保证使用正确类型处理器。
  注意:如果null被当作值来传递,对于所有可能为空的列,JDBC Type是需要的。以可以自己通过阅读预处理语句的setNull()方法的JavaDocs文档来研究这个。
  为了自定义类型处理器,你可以指定一个确定的类型处理器类(或别名),比如:
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
  尽管它看起来繁琐,但是实际上是你很少设置它们其中之一。
  对于数值类型,对于决定有多少数字是相关的,有一个数值范围。
#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}
  最后,mode属性允许你指定IN,OUT或INOUT 参数。如果参数为OUT或INOUT,
  参数对象属性的真实值将会被改变,就像你期望你需要你个输出参数。如果mode 为OUT(或INOUT),而且jdbcType 为CURSOR(也就是Oracle的REFCURSOR),你必须指定一个resultMap 来映射结果集到参数类型。要注意这里的javaType 属性是可选的,如果左边的空白是jdbcType的CURSOR类型,它会自动地被设置为结果集。
#{department,
  mode=OUT,
  jdbcType=CURSOR,
  javaType=ResultSet,
  resultMap=departmentResultMap}
MyBatis也支持很多高级的数据类型,比如结构体,但是当注册out参数时你必须告诉语句类型名称。比如(再次提示,在实际中不要像这样换行):
#{middleInitial,
  mode=OUT,
  jdbcType=STRUCT,
  jdbcTypeName=MY_TYPE,
  resultMap=departmentResultMap}
  尽管所有这些强大的选项很多时候你只简单指定属性名,MyBatis会自己计算剩余的。
  最多的情况是你为jdbcType 指定可能为空的列名。
#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}
  字符串替换
  默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并以它为背景设置安全的值(比如?)。这样做很安全,很迅速也是首选做法,有时你只是想直接在SQL语句中插入一个不改变的字符串。比如,像ORDER BY,你可以这样来使用:
ORDER BY ${columnName}
  这里MyBatis不会修改或转义字符串。
  重要:接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的。这会导致潜在的SQL注入攻击,因此你不应该允许用户输入这些字段,或者通常自行转义并检查。

resultMap

resultMap 元素是MyBatis中最重要最强大的元素。它就是让你远离90%的需要从结果集中取出数据的JDBC代码的那个东西,而且在一些情形下允许你做一些JDBC不支持的事情。事实上,编写相似于对复杂语句联合映射这些等同的代码,也许可以跨过上千行的代码。ResultMap的设计就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们的关系。 你已经看到简单映射语句的示例了,但没有明确的resultMap。比如:
<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>
这样一个语句简单作用于所有列被自动映射到HashMap的键上,这由resultType 属性指定。这在很多情况下是有用的,但是HashMap不能很好描述一个领域模型。那样你的应用程序将会使用JavaBeans或POJOs(Plain Old Java Objects,普通Java对象)来作为领域模型。MyBatis对两者都支持。看看下面这个JavaBean:

  1. package com.someapp.model;
  2.  
  3. public class User {
  4. private int id;
  5. private String username;
  6. private String hashedPassword;
  7.  
  8. public int getId() {
  9. return id;
  10. }
  11.  
  12. public void setId(int id) {
  13. this.id = id;
  14. }
  15.  
  16. public String getUsername() {
  17. return username;
  18. }
  19.  
  20. public void setUsername(String username) {
  21. this.username = username;
  22. }
  23.  
  24. public String getHashedPassword() {
  25. return hashedPassword;
  26. }
  27.  
  28. public void setHashedPassword(String hashedPassword) {
  29. this.hashedPassword = hashedPassword;
  30. }
  31. }

基于JavaBean的规范,上面这个类有3个属性:id,username和hashedPassword。这些在select语句中会精确匹配到列名。

这样的一个JavaBean可以被映射到结果集,就像映射到HashMap一样简单。
<select id=”selectUsers” parameterType=”int”
  resultType=”com.some app.model.User”>
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>
要记住类型别名是你的伙伴。使用它们你可以不用输入类的全路径。比如:
<!-- In Config XML file -->
<typeAlias type=”com.some app.model.User” alias=”User”/>
<!-- In SQL Mapping XML file -->
<select id=”selectUsers” parameterType=”int” resultType=”User”>
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>
这些情况下,MyBatis会在幕后自动创建一个ResultMap,基于属性名来映射列到JavaBean的属性上。如果列名没有精确匹配,你可以在列名上使用select字句的别名(一个基本的SQL特性)来匹配标签。比如:
<select id=”selectUsers” parameterType=”int” resultType=”User”>
  select
  user_id as “id”,
  user_name as “userName”,
  hashed_password as “hashedPassword”
  from some_table
  where id = #{id}
</select>

ResultMap最优秀的地方你已经了解了很多了,但是你还没有真正的看到一个。这些简单的示例不需要比你看到的更多东西。只是出于示例的原因,让我们来看看最后一个示例中外部的resultMap 是什么样子的,这也是解决列名不匹配的另外一种方式。
<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="username"/>
  <result property="password" column="password"/>
</resultMap>
引用它的语句使用resultMap 属性就行了(注意我们去掉了resultType属性)。比如:
<select id=”selectUsers” parameterType=”int” resultMap=”userResultMap”>
  select user_id, user_name, hashed_password
  from some_table
  where id = #{id}
</select>
如果世界总是这么简单就好了。

五、SQL映射的XML文件的更多相关文章

  1. SQL 映射的 XML 文件

    MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方. 对于所有的力量, SQL映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大 ...

  2. MyBatis学习(四)XML配置文件之SQL映射的XML文件

    SQL映射文件常用的元素: 1.select 查询语句是MyBatis最常用的语句之一. 执行简单查询的select元素是非常简单的: <select id="selectUser&q ...

  3. SpringBoot项目里,让TKmybatis支持可以手写sql的Mapper.xml文件

    SpringBoot项目通常配合TKMybatis或MyBatis-Plus来做数据的持久化. 对于单表的增删改查,TKMybatis优雅简洁,无需像传统mybatis那样在mapper.xml文件里 ...

  4. IDEA Mybatis 找不到映射器xml文件

    用IDEA新建了一个测试MyBatis工程,工程目录如下 其中config是MyBatis的配置文件,内容如下 <?xml version="1.0" encoding=&q ...

  5. mybatis 找不到映射器xml文件 (idea)

    原因是: idea不会编译src的java目录的xml文件 所以解决思路就是:将IDEA maven项目中src源代码下的xml等资源文件编译进classes文件夹 具体操作方法就是:配置maven的 ...

  6. Could not find resource——mybatis 找不到映射器xml文件

    今天用IDEA写Mybatis的时候,测试报了如图所示的错,恶心死我了,后来解决了,总结一下,防止下回跳坑,当然,也是做一个分享,如果有朋友遇到这个错,希望有所帮助 Error parsing SQL ...

  7. ms sql server读取xml文件存储过程-sp_xml_preparedocument

    最近要在存储过程中读取xml中节点的值,然后进行sql操作: 要使用到的系统存储过程如下:sp_xml_preparedocument create procedure [dbo].[pro_Test ...

  8. 【转】Mybatis 3.1中 Mapper XML 文件 的学习详解

    MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL 映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 ...

  9. Mybatis 3.1中 Mapper XML 文件 的学习详解(转载)

    MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL 映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 ...

随机推荐

  1. 异常: http://www.ly.com/news/visa.html: java.io.IOException: unzipBestEffort returned null

    nutch 运行时异常: http://www.ly.com/news/visa.html: java.io.IOException: unzipBestEffort returned null 参考 ...

  2. How to steal any developer's local database

    原文链接: http://bouk.co/blog/hacking-developers/ If you’re reading this and you’re a software developer ...

  3. java对xml文件做增删改查

    http://www.cnblogs.com/wangchenyang/archive/2011/08/23/2150530.html http://www.blogjava.net/weishuan ...

  4. SecureCRT 中文乱码问题

    1.修改远程linux机器的配置 [root@rhel ~]#vi /etc/sysconfig/i18n 把LANG改成支持UTF-8的字符集 如: LANG=”zh_CN.UTF-8″ 或者是 L ...

  5. ZOJ 2110 Tempter of the Bone(DFS)

    点我看题目 题意 : 一个N×M的迷宫,D是门的位置,门会在第T秒开启,而开启时间小于1秒,问能否在T秒的时候到达门的位置,如果能输出YES,否则NO. 思路 :DFS一下就可以,不过要注意下一终止条 ...

  6. HDU4523+简单

    题意很简单. 一次最多多切出一条边! 其余的就没什么好说的了 import java.util.*; import java.math.*; public class Main{ public sta ...

  7. easyui源码翻译1.32--Combo(自定义下拉框)

    前言 扩展自$.fn.validatebox.defaults.使用$.fn.combo.defaults重写默认值对象.下载该插件翻译源码 自定义下拉框显示一个可编辑的文本框和下拉面板在html页面 ...

  8. ANDROID_MARS学习笔记_S01原始版_002_实现计算乘积及menu应用

    一.代码 1.xml(1)activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk ...

  9. leetcode面试准备: Game of Life

    leetcode面试准备: Game of Life 1 题目 According to the Wikipedia's article: "The Game of Life, also k ...

  10. VJP1071新年趣事之打牌(背包+输出路径)

    简单的01背包 保存下方案总数 其实就是dp[v]值 输出路径dfs一下 #include <iostream> #include<cstdio> #include<cs ...