0

0

深入浅出Mybatis系列(八)---mapper映射文件配置之select、resultMap

黄舟

黄舟

发布时间:2017-03-02 11:03:41

|

2002人浏览过

|

来源于php中文网

原创

上篇《深入浅出Mybatis系列(七)---mapper映射文件配置之insert、update、delete》介绍了insert、update、delete的用法,本篇将介绍select、resultMap的用法。select无疑是我们最常用,也是最复杂的,mybatis通过resultMap能帮助我们很好地进行高级映射。下面就开始看看select 以及 resultMap的用法:

先看select的配置吧:

<select        <!--  1. id (必须配置)
        id是命名空间中的唯一标识符,可被用来代表这条语句。 
        一个命名空间(namespace) 对应一个dao接口, 
        这个id也应该对应dao里面的某个方法(相当于方法的实现),因此id 应该与方法名一致  -->
     
     id="selectPerson"     
     <!-- 2. parameterType (可选配置, 默认为mybatis自动选择处理)
        将要传入语句的参数的完全限定类名或别名, 如果不配置,mybatis会通过ParameterHandler 根据参数类型默认选择合适的typeHandler进行处理
        parameterType 主要指定参数类型,可以是int, short, long, string等类型,也可以是复杂类型(如对象) -->
     parameterType="int"     
     <!-- 3. resultType (resultType 与 resultMap 二选一配置)
         resultType用以指定返回类型,指定的类型可以是基本类型,可以是java容器,也可以是javabean -->
     resultType="hashmap"     
     <!-- 4. resultMap (resultType 与 resultMap 二选一配置)
         resultMap用于引用我们通过 resultMap标签定义的映射类型,这也是mybatis组件高级复杂映射的关键 -->
     resultMap="personResultMap"     
     <!-- 5. flushCache (可选配置)
         将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:false -->
     flushCache="false"     
     <!-- 6. useCache (可选配置)
         将其设置为 true,将会导致本条语句的结果被二级缓存,默认值:对 select 元素为 true -->
     useCache="true"     
     <!-- 7. timeout (可选配置) 
         这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)-->
     timeout="10000"     
     <!-- 8. fetchSize (可选配置) 
         这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等。默认值为 unset(依赖驱动)-->
     fetchSize="256"     
     <!-- 9. statementType (可选配置) 
         STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED-->
     statementType="PREPARED"     
     <!-- 10. resultSetType (可选配置) 
         FORWARD_ONLY,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一个,默认值为 unset (依赖驱动)-->
     resultSetType="FORWARD_ONLY">

配置看起来总是这么多,不过实际常用的配置也就那么几个, 根据自己的需要吧,上面都已注明是否必须配置。

下面还是上个demo及时练练手吧:

------------------------------------------------------------------------下面是针对select 的练手demo---------------------------------------------------------------------------------------

数据库:新增两张表(t_course, t_student)

t_course:

t_student:

其中,1个student可选择多个course进行学习。

我们还是拿上篇文章的demo, 继续写:

增加后,项目目录如下所示:

 

Course.java:

package com.dy.entity;public class Course {    private int id;    private String name; 
    private int deleteFlag;    
    public int getId() {        return id;
    }    public void setId(int id) {        this.id = id;
    }    public String getName() {        return name;
    }    public void setName(String name) {        this.name = name;
    }    public int getDeleteFlag() {        return deleteFlag;
    }    public void setDeleteFlag(int deleteFlag) {        this.deleteFlag = deleteFlag;
    }
    
}


Student.java:

package com.dy.entity;
import java.util.List;public class Student {    
private int id;    
private String idCard;   
private String name;    
private List<Course> courseList;    
private int deleteFlag;    
    public Student(int id, String idCard, String name, List<Course> courseList, int deleteFlag) {        
    this.id = id;        
    this.idCard = idCard;        
    this.name = name;        
    this.courseList = courseList;        
    this.deleteFlag = deleteFlag;
    }    
    public int getId() {        return id;
    }    public void setId(int id) {        this.id = id;
    }    public String getIdCard() {        return idCard;
    }    public void setIdCard(String idCard) {        this.idCard = idCard;
    }    public String getName() {        return name;
    }    public void setName(String name) {        this.name = name;
    }    public List<Course> getCourseList() {        return courseList;
    }    public void setCourseList(List<Course> courseList) {        this.courseList = courseList;
    }    public int getDeleteFlag() {        return deleteFlag;
    }    public void setDeleteFlag(int deleteFlag) {        this.deleteFlag = deleteFlag;
    }
}


CourseDao.java:

package com.dy.dao;import com.dy.entity.Course;public interface CourseDao {    
public Course findCourseById(int courseId);
    
}

StudentDao.java:


package com.dy.dao;import com.dy.entity.Student;public interface StudentDao {    
public Student findStudentById(String idCard);
}

courseDao.xml:

<mapper namespace="com.dy.dao.CourseDao">
    
    <!-- 
        1.此处直接将resultType 设置为course, 一看就知道我设置了别名吧,如果没有设置别名,那么resultType = com.dy.entity.Course。
         2.可能细心的你会发现:Course.java中的属性名与数据库字段名不一致,下面,我就在sql语句中用了as, 使之匹配,当然方法不止一种,
             在学习了resultMap之后,你能看到一种更直观优雅的方式去将javabean中的属性与数据库字段名保持一致
         3.findCourseById 与CourseDao中findCourseById方法对应, 那么传入的参数名称以及类型也应该保持对应关系。
         4.可以看到,在sql语句中,通过#{}表达式可以获取参数。
         5.下面这条sql语句,实际上的形式是怎么样的?还记得之前说过,mybatis默认为preparedStatement吧,那么,用我们jdbc代码来看,它其实就是:
             select course_id as id, course_name as name, course_delete_flg as deleteFlag from t_course where course_id=?     -->
    <select id="findCourseById"  resultType="course" >
        select course_id as id, course_name as name, course_delete_flg as deleteFlag from t_course where course_id=#{courseId}    </select>
    </mapper>

CourseDaoTest.java:

package com.dy.dao;
import java.io.IOException;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.junit.Test;
import com.dy.entity.Course;public class CourseDaoTest {

    @Test    public void findCourseById() {
        SqlSessionFactory sqlSessionFactory = getSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession(); 
        CourseDao courseDao = sqlSession.getMapper(CourseDao.class);
        Course course = courseDao.findCourseById(1);
    }    
    
    //Mybatis 通过SqlSessionFactory获取SqlSession, 然后才能通过SqlSession与数据库进行交互
    private static SqlSessionFactory getSessionFactory() {  
        SqlSessionFactory sessionFactory = null;  
        String resource = "mybatis-conf.xml";  
        try {  
            sessionFactory = new SqlSessionFactoryBuilder().build(Resources  
                    .getResourceAsReader(resource));
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
        return sessionFactory;  
    }  
}


上面的示例,我们针对course, 简单演示了 select的用法, 不过有个问题值得思考: 一个student可以对应多个course,  那么,在mybatis中如何处理这种一对多, 甚至于多对多,一对一的关系呢?

这儿,就不得不提到 resultMap 这个东西, mybatis的resultMap功能可谓十分强大,能够处理复杂的关系映射, 那么resultMap 该怎么配置呢? 别急,这就来了:

resultMap的配置:

<!-- 
        1.type 对应类型,可以是javabean, 也可以是其它
        2.id 必须唯一, 用于标示这个resultMap的唯一性,在使用resultMap的时候,就是通过id指定     -->
    <resultMap type="" id="">
    
        <!-- id, 唯一性,注意啦,这个id用于标示这个javabean对象的唯一性, 不一定会是数据库的主键(不要把它理解为数据库对应表的主键) 
            property属性对应javabean的属性名,column对应数据库表的列名
            (这样,当javabean的属性与数据库对应表的列名不一致的时候,就能通过指定这个保持正常映射了)        -->
        <id property="" column=""/>
        
        <!-- result与id相比, 对应普通属性 -->    
        <result property="" column=""/>
        
        <!-- 
            constructor对应javabean中的构造方法         -->
        <constructor>
            <!-- idArg 对应构造方法中的id参数 -->
            <idArg column=""/>
            <!-- arg 对应构造方法中的普通参数 -->
            <arg column=""/>
        </constructor>
        
        <!-- 
            collection,对应javabean中容器类型, 是实现一对多的关键 
            property 为javabean中容器对应字段名
            column 为体现在数据库中列名
            ofType 就是指定javabean中容器指定的类型        -->
        <collection property="" column="" ofType=""></collection>
        
        <!-- 
            association 为关联关系,是实现N对一的关键。
            property 为javabean中容器对应字段名
            column 为体现在数据库中列名
            javaType 指定关联的类型         -->
        <association property="" column="" javaType=""></association>
    </resultMap>


好啦,知道resutMap怎么配置后,咱们立即接着上面的demo来练习一下吧:

------------------------------------------------------------------下面是用resultMap处理一对多关系的映射的示例-------------------------------------------------------------

一个student对应多个course, 典型的一对多,咱们就来看看mybatis怎么配置这种映射吧:

studentDao.xml:

<mapper namespace="com.dy.dao.StudentDao">

    <!-- 这儿定义一个resultMap -->
    <resultMap type="student" id="studentMap">
    
        <!-- 
            数据库中主键是id, 但是我这儿却是指定idCard为主键,为什么? 
            刚刚讲了,id用来表示唯一性, 我们可以认为只要idCard一样,那么他就是同一个学生。
            如果此处用数据库中id, 那么mybatis将会认为数据库中每条记录都是一个student, 这显然不符合逻辑        -->
        <id property="idCard" column="stu_id_card"/>
        <result property="id" column="stu_id"/>
        <result property="name" column="stu_name"/>
        <result property="deleteFlag" column="stu_delete_flg"/>
        
        <!-- 
            这儿就是实现一对多的关键。 
            在Student中,courseList为List<Course>, 因此,ofType也应该与之对应(当然,我用了别名,不然要蛋疼的写全名了)。
            collection的子标签是在指定Course的映射关系(由于Course的javabean的属性名与数据库的列名不一致)        -->
        <collection property="courseList" column="stu_course_id" ofType="Course">
            <id property="id" column="course_id"/>
            <result property="name" column="course_name"/>
            <result property="deleteFlag" column="course_delete_flg"/>
        </collection>
    </resultMap>
    
    <!-- 这儿将返回类型设置成了上面指定的studentMap -->
    <select id="findStudentById" resultMap="studentMap">
        SELECT s.*, c.* FROM t_student s LEFT JOIN t_course c ON s.stu_course_id=c.course_id WHERE s.stu_id_card=#{idCard}    </select>
    </mapper>


StudentDaoTest.java:

package com.dy.dao;import java.io.IOException;
import java.util.List;
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.junit.Test;
import com.dy.entity.Course;import com.dy.entity.Student;public class StudentDaoTest {

    @Test    public void findCourseById() {
        SqlSessionFactory sqlSessionFactory = getSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession(); 
        StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
        Student student = studentDao.findStudentById("20140101");
        List<Course> courseList = student.getCourseList();        for (Course course: courseList) {
            System.out.println(course.getId() + "   " + course.getName());
        }
    }    
    
    //Mybatis 通过SqlSessionFactory获取SqlSession, 然后才能通过SqlSession与数据库进行交互
    private static SqlSessionFactory getSessionFactory() {  
        SqlSessionFactory sessionFactory = null;  
        String resource = "mybatis-conf.xml";  
        try {  
            sessionFactory = new SqlSessionFactoryBuilder().build(Resources  
                    .getResourceAsReader(resource));
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
        return sessionFactory;  
    }  
}

相信通过以上demo, 大家也能够使用mybatis的select 和 resultMap的用法了。上面demo只演示了一对多的映射,其实多对一、多对多也与它类似,所以我就没演示了,有兴趣的可以自己动手再做做。

好啦,本次就写到这儿了。(PS,生病一周了,所以到现在才更新博客)。

 以上就是深入浅出mybatis系列(八)---mapper映射文件配置之select、resultmap 的内容,更多相关内容请关注php中文网(www.php.cn)!

NexChatGPT
NexChatGPT

火爆全网的IDEA插件,支持IDEA全家桶

下载


热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

48

2026.02.28

Golang 工程化架构设计:可维护与可演进系统构建
Golang 工程化架构设计:可维护与可演进系统构建

Go语言工程化架构设计专注于构建高可维护性、可演进的企业级系统。本专题深入探讨Go项目的目录结构设计、模块划分、依赖管理等核心架构原则,涵盖微服务架构、领域驱动设计(DDD)在Go中的实践应用。通过实战案例解析接口抽象、错误处理、配置管理、日志监控等关键工程化技术,帮助开发者掌握构建稳定、可扩展Go应用的最佳实践方法。

44

2026.02.28

Golang 性能分析与运行时机制:构建高性能程序
Golang 性能分析与运行时机制:构建高性能程序

Go语言以其高效的并发模型和优异的性能表现广泛应用于高并发、高性能场景。其运行时机制包括 Goroutine 调度、内存管理、垃圾回收等方面,深入理解这些机制有助于编写更高效稳定的程序。本专题将系统讲解 Golang 的性能分析工具使用、常见性能瓶颈定位及优化策略,并结合实际案例剖析 Go 程序的运行时行为,帮助开发者掌握构建高性能应用的关键技能。

37

2026.02.28

Golang 并发编程模型与工程实践:从语言特性到系统性能
Golang 并发编程模型与工程实践:从语言特性到系统性能

本专题系统讲解 Golang 并发编程模型,从语言级特性出发,深入理解 goroutine、channel 与调度机制。结合工程实践,分析并发设计模式、性能瓶颈与资源控制策略,帮助将并发能力有效转化为稳定、可扩展的系统性能优势。

22

2026.02.27

Golang 高级特性与最佳实践:提升代码艺术
Golang 高级特性与最佳实践:提升代码艺术

本专题深入剖析 Golang 的高级特性与工程级最佳实践,涵盖并发模型、内存管理、接口设计与错误处理策略。通过真实场景与代码对比,引导从“可运行”走向“高质量”,帮助构建高性能、可扩展、易维护的优雅 Go 代码体系。

19

2026.02.27

Golang 测试与调试专题:确保代码可靠性
Golang 测试与调试专题:确保代码可靠性

本专题聚焦 Golang 的测试与调试体系,系统讲解单元测试、表驱动测试、基准测试与覆盖率分析方法,并深入剖析调试工具与常见问题定位思路。通过实践示例,引导建立可验证、可回归的工程习惯,从而持续提升代码可靠性与可维护性。

3

2026.02.27

漫蛙app官网链接入口
漫蛙app官网链接入口

漫蛙App官网提供多条稳定入口,包括 https://manwa.me、https

268

2026.02.27

deepseek在线提问
deepseek在线提问

本合集汇总了DeepSeek在线提问技巧与免登录使用入口,助你快速上手AI对话、写作、分析等功能。阅读专题下面的文章了解更多详细内容。

51

2026.02.27

AO3官网直接进入
AO3官网直接进入

AO3官网最新入口合集,汇总2026年可用官方及镜像链接,助你快速稳定访问Archive of Our Own平台。阅读专题下面的文章了解更多详细内容。

430

2026.02.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS教程
CSS教程

共754课时 | 38.5万人学习

【web前端】Node.js快速入门
【web前端】Node.js快速入门

共16课时 | 2.1万人学习

微信小程序开发之API篇
微信小程序开发之API篇

共15课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号