sql映射文件的几个顶级元素:

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


1.select


查询语句是使用 MyBatis 时最常用的元素之一。


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


id:在命名空间中唯一的标识符,可以被用来引用这条语句。

parameterType:将会传入这条语句的参数类的完全限定名或别名。

resultType:从这条语句中返回的期望类型的类的完全限定名或别名。注意集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用。

resultMap:命名引用外部的 resultMap。返回 map 是 MyBatis 最具力量的特性,对其有一个很好的理解的话,许多复杂映射的情形就能被解决了。使用 resultMap 或 ,但不能同时使用。

flushCache:将其设置为 true, 无论语句什么时候被调用,都会导致缓存被清空。默认值: false。
useCache:将其设置为 true,将会导致本条语句的结果被缓存。默认值: true。
timeout:这个设置驱动程序等待数据库返回请求结果,并抛出异常时间的最大等待值。默认不设置(驱动自行处理)。
fetchSize:这是暗示驱动程序每次批量返回的结果行数。默认不设置(驱动自行处理)。
statementType:STATEMENT,PREPARED 或 CALLABLE 的一种。这会让 使用选择使用 , 或 。默认值: 。

resultSetType:FORWARD_ONLY|SCROLL_SENSITIVE|SCROLL_INSENSITIVE中的一种。默认是不设置(驱动自行处理)。

2.insert,update,delete


 数据修改语句 insert, update 和 delete 在它们的实现中非常相似:


<insert  id="insertAuthor"   parameterType="domain.blog.Author"  flushCache="true"  statementType="PREPARED"
keyProperty=""   useGeneratedKeys=""  timeout="20000">
<update  id="insertAuthor"  parameterType="domain.blog.Author" flushCache="true"  statementType="PREPARED"  timeout="20000">
<delete  id="insertAuthor"  parameterType="domain.blog.Author"  flushCache="true"  statementType="PREPARED"  timeout="20000">

id:在命名空间中唯一的标识符,可以被用来引用这条语句。

parameterType:将会传入这条语句的参数类的完全限定名或别名。

flushCache将其设置为 true,不论语句什么时候被调用,都会导致缓存被清空。默认值: false。

timeout:这个设置驱动程序等待数据库返回请求结果,并抛出异常时间的最大等待值。默认不设置(驱动自行处理)。

statementType:STATEMENT,PREPARED 或 CALLABLE 的一种。这会让 使用选择使用 , 或 。默认值: 。

userGeneratedKeys:( 仅 对 insert MyBatis JDBC getGeneratedKeys MySQL SQL Server false。

keyProperty:(仅对 insert有用)标记一个属性, MyBatis getGeneratedKeys或者通过 insert 语句的 selectKey 子元素设置它的值。默认:不设置。





MyBatis JDBC 驱动不支持自动生成主键时的主键生成问题。

<insert id="insertAuthor" parameterType="domain.blog.Author">
   <selectKey keyProperty="id" resultType="int" order="BEFORE">
      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属性:


keyProperty:selectKey 语句结果应该被设置的目标属性。


resultType:结果的类型。 MyBatis MyBatis 允许任何简单类型用作主键的类型,包括字符串。

order:这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty AFTER,那么先执行插入语句,然后是 selectKey -这和如 数据库相似,可以在插入语句中嵌入序列调用。

statementType:和前面的相同, MyBatis STATEMENT, PREPARED CALLABLE PreparedStatement CallableStatement 类型。

3.sql


     这个元素可以被用来定义可重用的 SQL 代码段,可以包含在其他语句中。


<sql id=”userColumns”> id,username,password </sql>
<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>
     select <include refid=”userColumns”/>
     from some_table where id = #{id}
</select>


4.resultMap



 resultMap 元素是 MyBatis 中最重要最强大的元素。ResultMap 的设计就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们的关系。



<resultMap id="userResultMap" type="User">
   <id property="id" column="user_id" />
   <result property="username" column="user_name"/>
   <result property="password" column="hashed_password"/>
</resultMap>
<select id=”selectUsers” parameterType=”int” resultMap=”userResultMap”>
     select user_id, user_name, hashed_password from some_table  where id = #{id}
</select>



ResultMap:



 1.constructor:类在实例化时,用来注入结果到构造方法中。



ID ID 可以帮助提高整体效能



注入到构造方法的一个普通结果



一个 ID 结果; 标记结果作为 ID 可以帮助提高整体效能



注入到字段或 JavaBean 属性的普通结果



一个复杂的类型关联;许多结果将包成这种类型



嵌入结果映射 结果映射自身的关联,或者参考一个



复杂类型的集



嵌入结果映射 – 结果映射自身的集,或者参考一个



使用结果值来决定使用哪个结果映射



基于某些值的结果映射



嵌入结果映射 这种情形结果也映射它本身,因此可以包含很多相同的元素,或者它可以参照一个外部的结果映射。



id,result  



<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>


property: 映射到列结果的字段或属性。如果匹配的是存在的,和给定名称相同的 JavaBeans 的属性,那么就会使用。否则 MyBatis 将会寻找给定名称的字段。这两种情形你可以使用通常点式的复杂属性导航。比如,你可以这样映射一些东西:“ username”,或者映射到一些复杂的东西:“ address.street.number”。

column:从数据库中得到的列名,或者是列名的重命名标签。这也是通常和会传递给 resultSet.getString(columnName)方法参数中相同的字符串。



javaType:一个 类的完全限定名,或一个类型别名。如果你映射到一个 , 通常可以断定类型。然而,如果你映射到的是 ,那么你应该明确地指定 来保证所需的行为。


jdbcType:在这个表格之后的所支持的 JDBC 类型列表中的类型。 JDBC 类型是仅仅需要对插入,更新和删除操作可能为空的列进行处理。 这是 JDBC的需要,而不是 MyBatis JDBC -但仅仅对可能为空的值。


typeHandler:使用这个属性,你可以覆盖默认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理器的实现,或者是类型别名。


构造方法


<constructor>
   <idArg column="id" javaType="int"/>
   <arg column=”username” javaType=”String”/>
</constructor>



   为了向这个构造方法中注入结果, MyBatis 需要通过它的参数的类型来标识构造方法。Java 没有自查( 或反射)参数名的方法。所以当创建一个构造方法元素时,保证参数是按顺序排列的,而且数据类型也是确定的。
   属性有:column、javaType、jdbcType、typeHandler。


关联



<association property="author" column="blog_author_id" javaType=" Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
</association>


  关联元素处理“有一个”类型的关系。比如,一个博客有一个用户。关联映射就工作于这种结果之上。


MyBatis 在这方面会有两种不同的方式:



1.嵌套查询:通过执行另外一个 SQL 映射语句来返回预期的复杂类型。



2.嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集。



属性:



property:映射到列结果的字段或属性。如果匹配的是存在的,和给定名称相同的JavaBeans 的属性,那么就会使用。否则 将会寻找给定名称的字段。这两种情形你可以使用通常点式的复杂属性导航。

column:来 自 数 据 库 的 列 名 , 或 重 命 名 的 列 标 签 。 这 和 通 常 传 递 给resultSet.getString(columnName)方法的字符串是相同的。注意:要处理复合主键,你可以指定多个列名通过 column={prop1=col1,prop2=col2}” 这种语法来传递给嵌套查询语句。这会引起prop1 prop2 以参数对象形式来设置给目标嵌套查询语句。

javaType:



jdbcType:



typeHandler

嵌套查询:



select:另外一个映射语句的 ID,可以加载这个属性映射需要的复杂类型。获取的在列属性中指定的列的值将被传递给目标 select 语句作为参数。表格后面有一个详细的示例。



注意:要处理复合主键,你可以指定多个列名通过column={prop1=col1,prop2=col2}” 这种语法来传递给嵌套查询语句。这会引起prop1 prop2 以参数对象形式来设置给目标嵌套查询语句。

<resultMap id=”blogResult” type=”Blog”>
   <association property="author" column="blog_author_id" javaType="Author" select=”selectAuthor”/>
</resultMap>
<select id=”selectBlog” parameterType=”int” resultMap=”blogResult”>
   SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id=”selectAuthor” parameterType=”int” resultType="Author">
   SELECT * FROM AUTHOR WHERE ID = #{id}
</select>



这种方式很简单,但是对于大型数据集合和列表将不会表现很好。问题就是我们熟知的“ N+1 查询问题”。



MyBatis 能延迟加载这样的查询就是一个好处,因此你可以分散这些语句同时运行的消耗。然而,如果你加载一个列表,之后迅速迭代来访问嵌套的数据,你会调用所有的延迟加载,这样的行为可能是很糟糕的。

嵌套结果:



resultMap:这是结果映射的 ,可以映射关联的嵌套结果到一个合适的对象图中。这是一种替代方法来调用另外一个查询语句。这允许你联合多个表来合成到一个单独的结果集。这样的结果集可能包含重复,数据的重复组需要被分解,合理映射到一个嵌套的对象图。为了使它变得容易, MyBatis 让你“链接”结果映射,来处理嵌套结果。

<select id="selectBlog" parameterType="int" resultMap="blogResult">
select
   B.id as blog_id,
   B.title as blog_title,
   B.author_id as blog_author_id,
   A.id as author_id,
   A.username as author_username,
   A.password as author_password,
   A.email as author_email,
   A.bio as author_bio
   From Blog B left outer join Author A on B.author_id = A.id where B.id = #{id}
</select>
<resultMap id="blogResult" type="Blog">
   <id property=”blog_id” column="id" />
   <result property="title" column="blog_title"/>
   <association property="author" column="blog_author_id" javaType="Author" resultMap=”authorResult”/>
</resultMap>
<resultMap id="authorResult" type="Author">
   <id property="id" column="author_id"/>
   <result property="username" column="author_username"/>
   <result property="password" column="author_password"/>
   <result property="email" column="author_email"/>
   <result property="bio" column="author_bio"/>
</resultMap>

如果authorResult不重用的话:



<resultMap id="blogResult" type="Blog">
   <id property=”blog_id” column="id" />
   <result property="title" column="blog_title"/>
   <association property="author" column="blog_author_id" javaType="Author">
     <id property="id" column="author_id"/>
     <result property="username" column="author_username"/>
     <result property="password" column="author_password"/>
     <result property="email" column="author_email"/>
     <result property="bio" column="author_bio"/>
   </association>
</resultMap>



集合



<collection property="posts" ofType="domain.blog.Post">//ofType用来指定集合的类
   <id property="id" column="post_id"/>
   <result property="subject" column="post_subject"/>
   <result property="body" column="post_body"/>
</collection>



集合的嵌套查询:


<resultMap id=”blogResult” type=”Blog”>
   <collection property="posts" javaType=”ArrayList” column="blog_id" ofType="Post" select=”selectPostsForBlog”/>
</resultMap>

<select id=”selectBlog” parameterType=”int” resultMap=”blogResult”>
   SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id=”selectPostsForBlog” parameterType=”int” resultType="Author">
   SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>



集合的嵌套结果:



<select id="selectBlog" parameterType="int" resultMap="blogResult">
select
   B.id as blog_id,
   B.title as blog_title,
   B.author_id as blog_author_id,
   P.id as post_id,
   P.subject as post_subject,
   P.body as post_body,
from Blog B left outer join Post P on B.id = P.blog_id where B.id = #{id}
</select>


<resultMap id="blogResult" type="Blog">
   <id property=”id” column="blog_id" />
   <result property="title" column="blog_title"/>
   <collection property="posts" ofType="Post">
     <id property="id" column="post_id"/>
     <result property="subject" column="post_subject"/>
     <result property="body" column="post_body"/>
   </collection>
</resultMap>




鉴别器



<discriminator javaType="int" column="draft">
   <case value="1" resultType="DraftPost"/>
</discriminator>


  有时一个单独的数据库查询也许返回很多不同(但是希望有些关联)数据类型的结果集。鉴别器元素就是被设计来处理这个情况的,还有包括类的继承层次结构。鉴别器非常容易理解,因为它的表现很像 Java 语言中的 语句。


  在这个示例中, MyBatis 会从结果集中得到每条记录,然后比较它的 vehicle 类型的值。如果它匹配任何一个鉴别器的实例,那么就使用这个实例指定的结果映射。 换句话说,这样做完全是剩余的结果映射被忽略(除非它被扩展,这在第二个示例中讨论)。 如果没有任何一个实例相匹配,那么 MyBatis 仅仅使用鉴别器块外定义的结果映射。

 


<resultMap id="vehicleResult" type="Vehicle">
   <id property=”id” column="id" />
   <result property="vin" column="vin"/>
   <result property="year" column="year"/>
   <result property="make" column="make"/>
   <result property="model" column="model"/>
   <result property="color" column="color"/>
   <discriminator javaType="int" column="vehicle_type">
     <case value="1" resultMap="carResult"/>
     <case value="2" resultMap="truckResult"/>
     <case value="3" resultMap="vanResult"/>
     <case value="4" resultMap="suvResult"/>
   </discriminator>
</resultMap>