MyBatis教程--XML映射器(四)
最全最详细的介绍:Mybatis官网
1 select
查询语句是 MyBatis 中最常用的元素之一——光能把数据存到数据库中价值并不大,还要能重新取出来才有用,多数应用也都是查询比修改要频繁。 MyBatis 的基本原则之一是:在每个插入、更新或删除操作之间,通常会执行多个查询操作。因此,MyBatis 在查询和结果映射做了相当多的改进。一个简单查询的 select 元素是非常简单的。比如:
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
这个语句名为 selectPerson,接受一个 int(或 Integer)类型的参数,并返回一个 HashMap 类型的对象,其中的键是列名,值便是结果行中的对应值。
select 元素属性:
<select
id="selectPerson"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">
2 insert, update 和 delete
数据变更语句 insert,update 和 delete 的实现非常接近:
<insert
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20">
<update
id="updateAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
<delete
id="deleteAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
在插入语句里面有一些额外的属性和子元素用来处理主键的生成,并且提供了多种生成方式:
- 如果数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置为主键就可以了
<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id">
insert into t_user(username,password)
values (#{username},#{password})
</insert>
- 对于不支持自动生成主键列的数据库和可能不支持自动生成主键的 JDBC 驱动,MyBatis还可以通过selectKey来实现
<insert id="insertAuthor">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select s_user.next form dual
</selectKey>
insert into t_user
(id, username, password)
values
(#{id}, #{username}, #{password})
</insert>
在上面的示例中,首先会运行 selectKey 元素中的语句,并设置 t_user的 id,然后才会调用插入语句。这样就实现了数据库自动生成主键类似的行为,同时保持了 Java 代码的简洁。
selectKey 元素描述如下:
<selectKey
keyProperty="id"
resultType="int"
order="BEFORE"
statementType="PREPARED">
3 sql
这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用。 参数可以静态地(在加载的时候)确定下来,并且可以在不同的 include 元素中定义不同的参数值。
<sql id="usertable">
${tableName}
</sql>
<sql id="userinclude">
from
<include refid="${include_target}"/>
</sql>
<select id="queryUserById" parameterType="int" resultType="User">
select
id, password, username
<include refid="userinclude">
<property name="include_target" value="usertable"/>
<property name="tableName" value="t_user"/>
</include>
where id = #{id}
</select>
以上xml会被解析为select id, password, username from t_user where id = ?
3.1 参数
sql的参数可以指定java类型,数据库类型和类型处理器
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
对于数值类型,还可以设置 numericScale 指定小数点后保留的位数
#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}
mode 属性允许你指定 IN,OUT 或 INOUT 参数。如果参数的 mode 为 OUT 或 INOUT,将会修改参数对象的属性值,以便作为输出参数返回。 如果 mode 为 OUT(或 INOUT),而且 jdbcType 为 CURSOR(也就是 Oracle 的 REFCURSOR),你必须指定一个 resultMap 引用来将结果集 ResultMap 映射到参数的类型上。要注意这里的 javaType 属性是可选的,如果留空并且 jdbcType 是 CURSOR,它会被自动地被设为 ResultMap。
#{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}
3.2 字符串替换(${})
当 SQL 语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用
@Select("select * from t_user where id = #{id}")
User findById(@Param("id") long id);
@Select("select * from t_user where username= #{name}")
User findByName(@Param("name") String name);
可以写成
@Select("select * from t_user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);
4 结果映射
resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
User.java
package com.jing.model;
public class User {
private int id;
private String userName;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
t_user表
CREATE TABLE `t_user` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`pwd` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
我们可以看出t_user表的name和pwd跟User对象userName和password是不对应的这样Mybatis无法正常对User对象进行复制,我们需要一个映射关系
<select id="queryAllUser" resultType="User">
select * from t_user
</select>
转换成
<resultMap id="userResultMap" type="User">
<id property="id" column="id" />
<result property="userName" column="name"/>
<result property="password" column="pwd"/>
</resultMap>
<select id="queryAllUser" resultMap="userResultMap">
select * from t_user
</select>
5 高级结果映射
高级结果映射过于复杂可以参考Mybatis官网
<!-- 非常复杂的结果映射 -->
<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
<association property="author" 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"/>
<result property="favouriteSection" column="author_favourite_section"/>
</association>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<association property="author" javaType="Author"/>
<collection property="comments" ofType="Comment">
<id property="id" column="comment_id"/>
</collection>
<collection property="tags" ofType="Tag" >
<id property="id" column="tag_id"/>
</collection>
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
</collection>
</resultMap>