Mybatis(二):Mybatis的映射文件sqlmapper详解
MyBatis 真正的力量是在映射语句中。这里是奇迹发生的地方。对于所有的力量,SQL 映射的 XML 文件是相当的简单。当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 95%的代码量。MyBatis 的构建就是聚焦于 SQL 的,使其远离于普通的方式。
SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):
- cache – 配置给定命名空间的缓存。
- cache-ref – 从其他命名空间引用缓存配置。
- resultMap – 最复杂,也是最有力量的元素,用来描述如何从数据库结果集中来加载你的对象。
- parameterMap – 已经被废弃了!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除。这里不会记录。
- sql – 可以重用的 SQL 块,也可以被其他语句引用。
- insert – 映射插入语句
- update – 映射更新语句
- delete – 映射删除语句
- select – 映射查询语句
1)cache
参阅这篇文章里的二级缓存段落 MyBatis缓存详解
2)sql
用来定义可重用的sql语句块。
<sql id="column">
name,species,sex
</sql>
然后在sql映射中用<include/>标签引入:
<select id="selectPetByName" parameterType="string" resultType="hashmap">
select
<include refid="column"/>
from pet
where name = #{name}
</select>
这样就可以减少大量重复的sql书写工作。
3)resultMap
resultMap是mybatis中最强大最有用的配置,它可以帮助我们告别繁琐的while + resultSet.get(..) 而实现自动封装。
对于简单的sql查询,不需要配置resultMap,用hashmap来封装结果集会更好,这样会以字段名称为key,字段值为value来封装结果集:
<select id="selectAllColumn" parameterType="string" resultType="hashmap">
select <include refid="column"/> from pet where name = #{name}
</select>
但有时我们需要得到一个JavaBean对象,有两种方式可以实现,一种用reusltType来制定结果类型,另一种用resultMap来映射结果集和JavaBean对象:
第一种方式:
<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:设置每次查询的最大返回结果,通常不设置改属性。
Mybatis(二):Mybatis的映射文件sqlmapper详解的更多相关文章
- mybatis映射文件mapper详解
mapper.xml映射文件主要是用来编写sql语句的,以及一些结果集的映射关系的编写,还有就是缓存的一些配置等等. 1.<select>元素 <select>元素就是sql查 ...
- 转载 Spring、Spring MVC、MyBatis整合文件配置详解
Spring.Spring MVC.MyBatis整合文件配置详解 使用SSM框架做了几个小项目了,感觉还不错是时候总结一下了.先总结一下SSM整合的文件配置.其实具体的用法最好还是看官方文档. ...
- MyBatis 源码分析 - 映射文件解析过程
1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...
- Spring MVC、MyBatis整合文件配置详解
Spring:http://spring.io/docs MyBatis:http://mybatis.github.io/mybatis-3/ Building a RESTful Web Serv ...
- 二:SQL映射文件
二:SQL映射文件 1.SQL映射文件: (1)mapper:映射文件的根元素节点,只有一个属性namespace(命名空间) 作用:用于区分不同的mapper全局唯一 绑定dao接口即面向接口编程, ...
- [转]文件IO详解(二)---文件描述符(fd)和inode号的关系
原文:https://www.cnblogs.com/frank-yxs/p/5925563.html 文件IO详解(二)---文件描述符(fd)和inode号的关系 ---------------- ...
- MyBatis 一级缓存、二级缓存全详解(一)
目录 MyBatis 一级缓存.二级缓存全详解(一) 什么是缓存 什么是MyBatis中的缓存 MyBatis 中的一级缓存 初探一级缓存 探究一级缓存是如何失效的 一级缓存原理探究 还有其他要补充的 ...
- 2017.3.31 spring mvc教程(二)核心流程及配置详解
学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...
- 史上最全的maven pom.xml文件教程详解
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...
随机推荐
- 51nod 最长单增子序列(动态规划)
最长单增子序列 (LIS Longest Increasing Subsequence)给定一个数列,从中删掉任意若干项剩余的序列叫做它的一个子序列,求它的最长的子序列,满足子序列中的元素是单调递增的 ...
- 51nod 编辑距离问题(动态规划)
编辑距离问题 给定两个字符串S和T,对于T我们允许三种操作:(1) 在任意位置添加任意字符(2) 删除存在的任意字符(3) 修改任意字符 问最少操作多少次可以把字符串T变成S? 例如: S= “AB ...
- CentOS下MySQL主从复制,读写分离
1.环境:所有系统都是CentOS5.5 mysql-5.6.31-2.el5,MySQL中都没有数据 主服务器IP为192.168.128.230 从服务器IP为192.168.128.235 代理 ...
- wildfly8.1部署注意事项
wildfly8.1部署注意事项 jboss 最近新项目上线,本人部署过程中总结了以下几点比较关键的地方,看是否对大家有用处 服务器改成支持外网访问 在standalone.xml文件中找到 ...
- [CF983E]NN country
题意:给一棵树,有许多条巴士线路$(a_i,b_i)$(巴士在路径上每个点都会停车),多次询问从一点到另一点最少要坐多少次巴士 首先dfs一遍预处理出一个点向上坐$2^k$次巴士能到的最浅点,于是我们 ...
- 【二分法】【尺取法】bzoj2348 [Baltic 2011]Plagiarism
一开始以为死于精度……调了半天发现死于long long…… 一.二分法: #include<cstdio> #include<cstring> #include<alg ...
- 【动态规划】【零一背包】CODEVS 1014 装箱问题 2001年NOIP全国联赛普及组
#include<cstdio> #include<algorithm> using namespace std; ],f[]; int main() { scanf(&quo ...
- 工作流Activiti新手入门学习路线整理
写在前面: 最近项目中使用到了工作流,虽然此部分不是自己需要完成的,但是也涉及到了要调用写的接口.正好有时间,就了解下,以便之后能在其他项目中用到时,不至于什么都不知道什么都不了解. 这里就主要整理下 ...
- 查看Java代码对应的汇编指令又一利器,JITWatch 转
http://www.tuicool.com/articles/IRrIRb3 时间 2015-05-13 08:00:00 Liuxinglanyue's Blog 原文 http://java ...
- [Linux] ubuntu 格式化u盘
$sudo fdisks -l 基本功,格式化命令,以格式化 /dev/sdb4 分区为例:$ sudo umount /dev/sdb4 # 必须先卸载该分区 # 格式化为 FAT 分区$ s ...