MyBatis-配置SQL映射文件

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 标签,导进语句中。

像这些我们需要查询的字段,也可以这样子搞。

留言区

还能输入500个字符