MyBatis的XML映射文件只有几个顶级元素:
cache:对给定命名空间缓存配置
cache-ref:对其他命名空间缓存配置的引用
resultMap:最复杂的元素,用以描述如何从数据库结果集中加载对象
sql:可被其他语句引用的可重用语句块
insert:映射插入语句
update:映射更新语句
delete:映射删除语句
select:映射查询语句
select:
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
该语句称作selectPerson,接受一个int(或Integer)类型的参数,并返回一个HashMap类型的对象。其中#{id}告诉MyBatis创建一个预处理语句(PreparedStatement)参数,上面的select映射大致等于(省略返回结果):
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);
从中可以看出使用MyBatis映射更加简单方便。
下面介绍select的属性:
<select
<!--命名空间中唯一标识符,可以被用来引用这条语句8 -->
id="selectPerson"
<!--可选属性,传入语句的参数类完全限定名或别名,可通过类型处理器推断具体传入语句的参数,默认值为unset -->
parameterType="int"
<!--返回期望类型的类的完全限定名或别名,如果返回的是集合,应该设置为集合包含的类型,而不是集合本身, resultType 或 resultMap不能同时使用-->
resultType="hashmap"
<!-同上- -->
resultMap="personResultMap"
<!--如果设置为true,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值为false -->
flushCache="false"
<!--设置为true后,将会导致本条语句的结果被二级缓存,默认值为true -->
useCache="true"
<!-- 驱动程序等待数据库返回请求结果的秒数,默认值为unset,依赖驱动-->
timeout="10"
<!--驱动提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等,默认值为未设置(依赖驱动) -->
fetchSize="256"
<!--STATEMENT,PREPARED 或 CALLABLE 中的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED -->
statementType="PREPARED"
<!--FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖驱动) -->
resultSetType="FORWARD_ONLY">
insert,update和delete:
属性介绍:
id:命名空间中唯一标识符,可被用来代表这条语句
parameterType:将要传入语句的参数的完全限定类名或别名,可选
flushCache:设置为true,都会导致本地缓存和二级缓存被清空,默认值为true
timeout:在抛出异常以前,驱动程序等待数据库返回请求结果的秒数,默认值为未设置(unset)
useGeneratedKeys:这会令MyBatis使用JDBC的getGeneratedKeys方法来取出数据库内部生成的主键,默认值为false
keyProperty:(仅对insert和update有用),唯一标记一个属性,MyBatis会通过getGeneratedKeys的返回值或者通过insert语句的selectKey 子元素设置它的键值
keyColumn:(仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望使用多个生成的列,也可以设置为逗号分隔的属性名称列表。
databaseId:如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。
如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上就 OK 了。例如,如果上面的 Author 表已经对 id 使用了自动生成的列类型,那么语句可以修改为:
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>
如果你的数据库还支持多行插入, 也可以传入一个 Author 数组或集合,并返回自动生成的主键:
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username, password, email, bio) values
<foreach item="item" collection="list" separator=",">
(#{item.username}, #{item.password}, #{item.email}, #{item.bio})
</foreach>
</insert>
sql:
该元素被用来定义可重用的SQL代码段,这些SQL代码可以被包含在其他语句中,它可以被静态地设置参数。在不同的包含语句中可以设置不同的值到参数占位符上:
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
该SQL片段可以被包含在其他语句中:
<select id="selectUsers" resultType="map">
select
<include refid="userColumns"><property name="alias" value="t1"/></include>,
<include refid="userColumns"><property name="alias" value="t2"/></include>
from some_table t1
cross join some_table t2
</select>
参数:
简单参数传递举例:
<select id="selectUsers" resultType="User">
select id, username, password
from users
where id = #{id}
</select>
复杂对象传递举例:
<insert id="insertUser" parameterType="User">
insert into users (id, username, password)
values (#{id}, #{username}, #{password})
</insert>
参数中指定特殊数据类型:
#{property,javaType=int,jdbcType=NUMERIC}
指定小数点后保留位数设置:
#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}
MyBatis 也支持很多高级的数据类型,比如结构体(structs),但是当使用 out 参数时,你必须显式设置类型的名称。比如(再次提示,在实际中要像这样不能换行):
#{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}
字符串替换:
直接在 SQL 语句中插入一个不转义的字符串。 比如,像 ORDER BY,可以这样来使用:
ORDER BY ${columnName}
当 SQL 语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。 举个例子,如果你想通过任何一列从表中 select 数据时,不需要像下面这样写:
@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);
@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);
@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);
可以只写一个方法:
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);
其中 ${column} 会被直接替换,而 #{value} 会被使用 ? 预处理。 因此可以像下面这样来达到上述功能:
User userOfId1 = userMapper.findByColumn("id", 1L);
User userOfNameKid = userMapper.findByColumn("name", "kid");
User userOfEmail = userMapper.findByColumn("email", "[email protected]");
结果映射:
ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了
举例:
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>