MyBatis中的SQL 映射文件只有很少的几个顶级元素(按照它们应该被定义的顺序如下):
cache – 给定命名空间的缓存配置。 cache-ref – 其他命名空间缓存配置的引用。 resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。 sql – 可被其他语句引用的可重用语句块。 insert – 映射插入语句 update – 映射更新语句 delete – 映射删除语句 select – 映射查询语句
1、select元素
select元素就是用来查询的,在select里嵌入SQL select查询语句,就像下边这样:
<select id="get" resultType="Employee" parameterType="int">
select * from employee where id=#{id};
</select>
其中 select元素中的id属性是必须的,它的值是对应Mapper接口中的一个方法,当调用这个接口就是调用这个sql。关于select元素常用的属性具体如下:
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句。这个是必须的属性 |
parameterType | 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。 |
resultType | 返回的期望类型的类的完全限定名或别名。这个属性是可选的 |
resultMap | 返回值类型是是个map集合,可用于多表联查后的结果MyBatis会封装成一个map返回,这个属性是可选的 |
flushCache | 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:false。这个属性是可选的 |
useCache | 将其设置为 true,将会导致本条语句的结果被二级缓存,默认值:对 select 元素为 true。这个属性是可选的 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。这个属性是可选的 |
2、insert update delete
insert update delete元素分别对应SQL语句中的insert、update、delete,分别实现对数据库记录的插入、更新和删除。他们可以有的属性值如下:
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句。这个是必须的属性 |
parameterType | 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。 |
useGeneratedKeys | (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键,默认值为false,这个属性是可选的。 | keyProperty | 指定实体类中的主键属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,他和useGeneratedKeys配合起来才能工作 |
flushCache | 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:true。这个属性是可选的 |
useCache | 将其设置为 true,将会导致本条语句的结果被二级缓存,默认值:对增删改元素为false。这个属性是可选的 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。这个属性是可选的 |
keyColumn | 指定数据表中的主键字段名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
3、resultMap
resultMap 元素是 MyBatis 中最重要最强大的元素。 ResultMap 的设计就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们的关系。
3.1 简单映射
例如下面这个例子::
<select id="getById" resultType="Employee" paramaterType="int">
select * from employee where id=#{id}
</select>
JavaBean是这样的:
package com.xzy.bean;
public class Employee {
/**
* JavaBean基本类型最好使用他的包装类型!!!
*/
private Long id;
private String empId;
private String empName;
private Integer empAge;
private String empSex;
//省略getter、setter....
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", empId='" + empId + '\'' +
", empName='" + empName + '\'' +
", empAge=" + empAge +
", empSex='" + empSex + '\'' +
'}';
}
}
Mybatis会将基于 JavaBean 的规范,这些 在 select 语句中会精确匹配到列名。这样一个语句简单作用于所有列被自动映射到 HashMap 的键上,这由 resultType 属性 指定。也就是说,对于resultType MyBatis会结果封装一个map返回。
3.2 高级映射
有时候我们避免不了多表联查,这样带来的问题是返回的结果类型中的一个字段在resultType中的不存在,这就会造成问题。MyBatis中使用resultMap来解决这个问题。 resultMap 元素有很多子元素和一个值得讨论的结构。 下面是 resultMap 标签中可以使用的属性如下:
resultMap: constructor - 类在实例化时,用来注入结果到构造方法中 idArg - ID 参数;标记结果作为 ID 可以帮助提高整体效能 arg - 注入到构造方法的一个普通结果 id – 一个 ID 结果;标记结果作为 ID 可以帮助提高整体效能 result – 注入到字段或 JavaBean 属性的普通结果 association – 一个复杂的类型关联;许多结果将包成这种类型 嵌入结果映射 – 结果映射自身的关联,或者参考一个 collection – 复杂类型的集 嵌入结果映射 – 结果映射自身的集,或者参考一个 discriminator – 使用结果值来决定使用哪个结果映射 case – 基于某些值的结果映射 嵌入结果映射 – 这种情形结果也映射它本身,因此可以包含很多相 同的元素,或者它可以参照一个外部的结果映射。
描述 | 描述 |
---|---|
id | 当前命名空间中的一个唯一标识,用于标识一个result map. |
type | 类的全限定名, 或者一个类型别名 |
autoMapping | 如果设置这个属性,MyBatis将会为这个ResultMap开启或者关闭自动映射。这个属性会覆盖全局的属性autoMappingBehavior。默认值为:unset。 |
下面是一个例子:
<!--StudentMapper.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xzy.mapper.StudentMapper">
<!--第一种多表联查的映射方式-->
<resultMap type="student" id="queryCName">
<id property="id" column="id"/>
<result property="sid" column="sid"/>
<result property="sname" column="sname"/>
<result property="majorIn" column="major_in"/>
<result property="sclass" column="sclass"/>
<result property="course.cname" column="cname"/>
</resultMap>
<!--查询某个同学所选的课程-->
<select id="getAll" parameterType="string" resultMap="queryCName">
select student.*,course.cname from student,course where student.cid=course.cid and student.sname=#{sname}
</select>
</mapper>
学生实体:Student.java
//JavaBean Student
package com.xzy.bean;
public class Student {
private Long id;
private String sid;
private String sname;
private String majorIn;
private String sclass;
private Course course;
//getter、setter...
@Override
public String toString() {
return "Student{" +
"id=" + id +
", sid='" + sid + '\'' +
", sname='" + sname + '\'' +
", majorIn='" + majorIn + '\'' +
", sclass='" + sclass + '\'' +
", cname=" + course.getCname() +
'}';
}
}
课程实体:Course.java
//JavaBean Course
package com.xzy.bean;
public class Course {
private Long id;
private String cid;
private String cname;
private Student student;
//省略getter、setter.....
@Override
public String toString() {
return "Course{" +
"id=" + id +
", cid='" + cid + '\'' +
", cname='" + cname + '\'' +
'}';
}
}
测试类AppTest.java
package com.xzy;
import com.xzy.bean.Course;
import com.xzy.bean.Student;
import com.xzy.mapper.CourseMapper;
import com.xzy.mapper.StudentMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Scanner;
/**
* Unit test for simple App.
*/
public class AppTest {
private static Logger log = Logger.getLogger(AppTest.class);
private static SqlSessionFactory sqlSessionFactory;
@Before
public void initLoad() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void selectAll() {
SqlSession session = sqlSessionFactory.openSession(true);
try{
StudentMapper sm=session.getMapper(StudentMapper.class);
List<Student> lists= sm.getAll("OKOK2");
if(null!=lists&&lists.size()>0) {
System.out.println("OKOK2同学选的课:");
for (Student list : lists) {
System.out.println(list.toString());
}
System.out.println("OK...");
}else{
System.out.println("没有这个人或该同学没有选课....");
}
}catch (Exception e){
System.out.println("查询失败。。。。");
}finally{
session.close();
}
}
}
运行结果:

cache 和cache-ref 的用法参考另一篇笔记MyBatis缓存配置
4、cache
cache标签是用于指定MyBatis的二级缓存的具体实现的。虽然MyBtis自带二级缓存的实现,但是MyBatis在缓存方面毕竟和专门的第三方缓存服务提供方还是有差距的,MyBatis官方也深知自己的不足,因此MyBatis提供了org.apache.ibatis.cache.Cache
接口,任何只要实现了这个接口的缓存中间件都可成为MyBatis二级缓存,具体的用法请参考我的博客MyBatis整合Redis作为二级缓存或MyBatis整合Encache作为二级缓存。
5、sql
我们在写这个 SQL 映射文件的时候,有很多重复的 SQL 语句。将这些重复的SQL 语句提取出来,称为 SQL 片段,给不同方法使用。 把我们的 SQL 语句提取出来,用 SQL 标签包起来。然后再用 include 标签,导进语句中。
像这些我们需要查询的字段,也可以这样子搞。