MyBatis 真正的力量是在映射语句中。这里是奇迹发生的地方。对于全部的力量,SQL 映射的 XML 文件是至关的简单。固然若是你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 95%的代码量。MyBatis 的构建就是聚焦于 SQL 的,使其远离于普通的方式。html
SQL 映射文件有不多的几个顶级元素(按照它们应该被定义的顺序):java
参阅这篇文章里的二级缓存段落 MyBatis缓存详解sql
用来定义可重用的sql语句块。数据库
<sql id="column"> name,species,sex </sql>
而后在sql映射中用<include/>标签引入:apache
<select id="selectPetByName" parameterType="string" resultType="hashmap"> select <include refid="column"/> from pet where name = #{name} </select>
这样就能够减小大量重复的sql书写工做。缓存
resultMap是mybatis中最强大最有用的配置,它能够帮助咱们告别繁琐的while + resultSet.get(..) 而实现自动封装。mybatis
对于简单的sql查询,不须要配置resultMap,用hashmap来封装结果集会更好,这样会以字段名称为key,字段值为value来封装结果集:dom
<select id="selectAllColumn" parameterType="string" resultType="hashmap"> select <include refid="column"/> from pet where name = #{name} </select>
但有时咱们须要获得一个JavaBean对象,有两种方式能够实现,一种用reusltType来制定结果类型,另外一种用resultMap来映射结果集和JavaBean对象:ide
第一种方式:post
<select id="selectOneByName" parameterType="string" resultType="com.mybatis.test.entity.Pet"> select <include refid="column"/> from pet where name = #{name} </select>
这样mybatis就会把查询出的结果封装到Pet对象中。
第二种方式:
配置resultMap
<resultMap type="com.mybatis.test.entity.Pet" id="petMap"> <result column="name" property="name" javaType="string" jdbcType="VARCHAR"/> <result column="species" property="species" javaType="string" jdbcType="VARCHAR" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/> <result column="sex" property="sex" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/> </resultMap>
在sql映射中配置resultMap:
<select id="cthSelect" resultMap="petMap"> select <include refid="column"/> from pet </select>
实际上应用第一种配置方式时,mybatis会在幕后根据字段名称自动建立一个resultMap。若表字段名称与JavaBean中的字段名称不匹配,还能够利用sql语句的as来修改sql结果集的字段名,使之与JavaBean中的字段名相匹配:
<select id="selectOneByName" parameterType="string" resultType="com.mybatis.test.entity.Pet"> select name as name, species as species, sex as sex from pet where name = #{name} </select>
但有的时候事情并无这么简单,咱们在不少状况下须要作一对多或多对一的联合查询,但把这些重组的字段再组合到一个新的bean对象中是不现实的,这样就须要对多个表和bean利用resultMap作联合配置,以知足实际的需求。
下面以经典的“部门”对“员工”为例,作一对多和多对一的映射配置:
Employee Bean:
private Integer id; private String employeeName; private Integer age; private Department department = new Department();
Department Bean:
private Integer id; private String departmentName; private List<Employee> employees;
一个部门对应多个员工,而一个员工属于一个部门,咱们分别从部门和员工的角度出发,来作一对多和多对一的映射。
员工-部门的多对一映射:
<resultMap type="com.mybatis.test.entity.Employee" id="employeeMap"> <!-- id : 一个 ID 结果;标记结果做为 ID 能够帮助提升总体效能. result : 注入到字段或 JavaBean 属性的普通结果 association : 一个复杂的类型关联;许多结果将包成这种类型. collection : 复杂类型的集 --> <id property="id" column="id"/> <result property="employeeName" column="name"/> <result property="age" column="age"/> <association property="department" javaType="Department"> <id property="id" column="id"/> <result property="departmentName" column="department_name"/> </association> </resultMap>
用<association/>来指定每个员工多对应的部门。
部门-员工的一对多映射:
<resultMap type="Department" id="departmentMap"> <id property="id" column="id"/> <result property="departmentName" column="department_name"/> <collection property="employees" ofType="Employee" column="dept_id"> <id property="id" column="id"/> <result property="employeeName" column="name"/> <result property="age" column="age"/> </collection> </resultMap>
利用<collection/>来制定可能是一方。在配置多对一关系时,须要在<collection/>中制定关联字段,column="dept_id",这样mybatis就会根据这个字段来找出全部属于该部门的员工,并将其封装到集合中。
在定义resultMap时,还能够利用javaType、jdbcType和typeHandler来实现java数据类型和数据库字段类型的对应关系及其特定的操做动做,eg:
在mybatis核心配置文件中生命自定义类型处理器:
<typeHandlers> <typeHandler javaType="string" jdbcType="VARCHAR" handler="com.mybatis.test.handler.MyStringTypeHandler"/> </typeHandlers>
自定义类型处理器:
package com.mybatis.test.handler; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; public class MyStringTypeHandler implements TypeHandler<String>{ @Override public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { if("".equals(parameter) || "null".equals(parameter) || parameter == null || "NULL".equals(parameter)){ parameter = "blank"; } ps.setString(i, parameter); } @Override public String getResult(ResultSet rs, String columnName) throws SQLException { String result = rs.getString(columnName); if("null".equals(result) || "".equals(result) || result == null || "NULL".equals(result)){ result = "blank"; } return result; } @Override public String getResult(ResultSet rs, int columnIndex) throws SQLException { String result = rs.getString(columnIndex); if("null".equals(result) || "".equals(result) || result == null || "NULL".equals(result)){ result = "blank"; } return result; } @Override public String getResult(CallableStatement cs, int columnIndex) throws SQLException { String result = cs.getString(columnIndex); if("null".equals(result) || "".equals(result) || result == null || "NULL".equals(result)){ result = "blank"; } return null; } }
该类型处理器既能够用于设置参数时、也能够用于获取结果时对空值的处理。
在resultMap中进行配置:
<resultMap type="com.mybatis.test.entity.Pet" id="petMap"> <result column="name" property="name" javaType="string" jdbcType="VARCHAR"/> <result column="species" property="species" javaType="string" jdbcType="VARCHAR" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/> <result column="sex" property="sex" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/> </resultMap>
这样,若是从数据库表中查询出的结果为null时,就会用自定义类型处理器中的方式进行处理。
在设置参数的时候能够像下面这样应用自定义类型处理器对参数进行处理:
<insert id="insertNullByMyTypeHandler" parameterType="Pet"> insert into pet (<include refid="column"/>) values ( #{name,jdbcType=UNDEFINED,javaType=string,handler=com.mybatis.test.handler.MyTypeHandler}, #{species}, #{sex} ) </insert>
3)insert、update、delete
这三个标签分别配置对应的sql语句,因为这三中sql都是DML,因此在用法上基本相同:
<insert id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty="" keyColumn="" useGeneratedKeys="" timeout="20"> <update id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20"> <delete id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20">
id:该sql语句在当前名称空间下的惟一标识符,用户调用该sql语句。
parameterType:sql语句的参数类型,能够是mybatis提供的别名(int、string、hashmap、list等),也能够是自定义相似。须要注意的是,若参数类型为hashmap或自定义bean等,在利用#{fieldName}取得参数的值时用到的名称须要与map中的key或bean中的字段名称保证一致,不然会取不到数据,若是是string或int等,则名称没有现实,只起到标识的做用。
flushCache:刷新缓存,若将该属性设置为true,则调用该sql时,会到时缓存被清空。默认为false。
statementType:设置预编译sql语句的方式,mybatis提供了三种:
STATEMENT,PREPARED,CALLABLE
默认是PREPARED类型。
timeout:设置获取数据库操做结果的最大等事件。默认不对其进行设置,有数据库取得来决定。
4)select
select语句是最经常使用的数据库操做,相对于DML操做,mybatis对select语句映射的支持明显更强。查询语句的特殊之处在于既有输入也有输出,下面对select语句映射作简要概述。
一个最简单的查询映射:
<select id="selectPerson" parameterType="int" resultType="hashmap"> SELECT * FROM PERSON WHERE ID = #{id} </select>
该语句按照id查询一条person记录,其中输入参数是int类型,虽然#{id}中的id与数据表中的id列名保存一致,但前面已经说过,对于基本数据类型的参数,名称没有现实,任何名字mybatis均可以取到参数的值。返回结果是hashmap,也就是Java中对应的HashMap,定义该结果类型后,mybatis会将查询结果封装到一个map对象中,key值为字段名称,value为该字段的值。
Mybatis对select标签提供了丰富的属性,以支持对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">
其中的本分属性前面已经介绍过,这里就不在冗述了。 useCache:配置二级缓存,当mybatis开启二级缓存时,查询有默认是应用二级缓存的,若不想将某一个DQL与二级缓存联系起来,可将该属性设置为false。 fetchSize:设置每次查询的最大返回结果,一般不设置改属性。