写在前面:十分感谢《深入浅出Mybatis技术原理与实战》这本书,大多数部分是书上的话,希望自己能在后面的文章中多写一些自己的理解。而且最重要的是!每次照书无脑敲的时候,都好羞愧啊(害羞脸)。后面一定注意这些问题。最后要感谢点赞、评论以及指正的朋友们,你们是坠吼的!!!
官方文档有云:
The resultMap element is the most important and powerful element in MyBatis.
resultMap元素是Mybatis中最重要也是最强大的元素。
作用是:定义映射规则、级联的更新、定制类型转换器。
其实我也是刚刚熟悉它,对它的使用并没有达到炉火纯青的地步,毕竟这个元素还是很复杂的。我只是把自己的理解过程记录下来,如果有错误,希望大家指正!
先说说他的结构:
<resultMap>
<constructor>
<idArg/>
<arg/>
</constructor>
<id/>
<result/>
<association>
<collection/>
<discriminator>
<case/>
</discriminator>
</resultMap>
眼花缭乱对吧!这里一点一点讲解:
constructor:用于配置构造方法。这里打个比方,当我们的实体类存在没有参数的构造方法时候。就不需要去配置它!比如我们有个Student类参数有id和name。
class Student{
private int id;
private String name;
}
熟悉java基础的同学知道,如果我们不去书写构造方法,那么java会自动帮我们建立一个无参数的构造方法:public Student(){}
但是如果我们写了带有参数的构造方法,这个无参构造方法将不会被自动创建!
所以对于这个构造方法:
public Student(int id,String name){
this.id = id;
this.name = name;
}
我们需要配置结果集的constructor:
<constructor>
<idArg column="id" javaType="int" />
<arg column="name" javaType="string"/>
<arg/>
</constructor>
.....
</resultMap>
也就代表着当我们不去写带参构造器的时候就不用去管constructor这个标签。如此即可,是不是理解起来很简单!
id和result:
id表示主键的列,允许多个主键,如果是多个的话,就是联合主键。
result配置的是实体类和数据库中列名的映射关系。
我们先不说后面的级联。先研究研究如何储存结果集。
储存结果集有两种方式:1.map 2.pojo(实体类)
但是用map这个方式说实话比较low。阅读性很差,所以pass。
我们使用POJO来存,好处是我们可以利用自动映射,还可以用select中的resultMap属性去配置映射集合。
举个小例子:
假设我们数据库中t_student表有两个字段:student_id和student_name。
我们POJO类中Student类有两个变量:studentId和studentName
。
我们的select语句如果这么写:(前提是其他文件已经写好)
<select id="getStudents">
select student_id,student_name from t_student
</select>
这样会发现我们获取到的ID号和姓名是空值,因为字段和变量名不是一一对应的。
我们需要这么写resultMap
<result id="studentResultMap" type="com.cream.pojo.Student">
<id property="studentId" column="student_id/>
<result property="studentName" column="student_name"/>
</result>
此时我们需要在select标签中加上 resultMap="studentResultMap" 即可配置成功。
数据也就可以直接取出来了!这几段我是凭自己记忆写的,之前测试的类被我删掉了,所以大致写个样子,只是为了一看就能马上回忆起来思路!
级联
接下来要说级联了,心里挺没底气的,毕竟是今天早上刚有点开窍,这东西真的是光看是很难理解的,只有自己动手敲一敲再想一想才能真正的悟出来!
Mybatis中的级联有三种:association、collection和discriminator。
discriminator很复杂,先研究完
级联呢,分为三种对应关系:
1.一对一
所谓一对一,打个比方:学生和学生证的关系。一名学生对应一张学生证。这个用association。
2.一对多
所谓一对多,打个比方:公司和员工,一家公司拥有很多员工。这个用collection。
3.多对多
所谓多对多,这个挺烦的:学生和课程。一名学生有很多课程。一门课程,有很多学生!那这个怎么办呢?比如说我们一般再建一张表学生课程表,专门存这个关系,双向使用一对多。达到多对多的关系。当然我们可以向这个表加一些比如说成绩之类的字段精确的存数据。
说了很多,估计看到这里一头雾水。接下来用实例讲解一下。
一对一
书上的例子很好:比如说学生和学生证,他们是一对一的关系。
那么当我们想要通过学生的id号查询到学生的时候,同时取得他的学生证信息,我们应该怎么设计呢?
思路应该是:把学生证(StudentSelfcard)这个类,当做类型放到学生类(Student)中去。
所以建学生类POJO的时候我们需要这么写:
学生类:
public class Student {
private StudentSelfcard studentSelfcard; //学生证类在学生类其中
...其他参数...
......getter and setter方法......
}
接下来,比如我们要通过学号取查询学生。那么Mapper应该这么写:
StudentSelfcardMapper.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.cream.dao.StudentSelfcardDao">
<resultMap id="studentSelfacrdMap" type="com.cream.pojo.StudentSelfcard">
<id property="id" column="id"/>
<result property="studentId" column="student_id"/>
<result property="native_" column="native"/>
<result property="issueDate" column="issue_date"/>
<result property="endDate" column="end_date"/>
<result property="note" column="note"/>
</resultMap>
<select id="findStudentSelfcardByStudentId" resultMap="studentSelfacrdMap">
SELECT id,student_id,native,issue_date,end_date,note
FROM t_student_selfcard WHERE student_id = #{studentId }
</select>
</mapper>
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.cream.dao.StudentDao">
<resultMap id="studentMap" type="com.cream.pojo.Student">
<id property="studentId" column="student_id"/>
<result property="cnname" column="cnname"/>
<result property="sex" column="sex"/>
<result property="note" column="note"/>
<association property="studentSelfcard" column="student_id"
select="com.cream.dao.StudentSelfcardDao.findStudentSelfcardByStudentId"/>
</resultMap>
<select id="getStudent" parameterType="int" resultMap="studentMap">
SELECT student_id,cnname,sex,note FROM t_student WHERE student_id = #{studentId }
</select>
</mapper>
关于上面的association讲解一下属性:
property: 映射到结果上的属性,其实就是我们通过关联又获取到了什么类型。
column:我们传送了什么参数过去,这里是student_id那传过去的就是它。
select:代表着由哪条SQL去查询。这里写的是接口以及里面的方法哦,不是xml文件。
在main函数中调用接口和方法即可知道,当我们确定的获取到一个学生信息的时候,同时我们获得了该学生的学生证信息。
一对多
这里想通过多对多去说,所以一对多不想说的太麻烦,先思考,当一对一的时候,是学生中包含着学生证。那么一对多可以用相同的思路来考虑:学生和成绩。一名学生对应着很多成绩,而成绩对应着一名学生。此时需要在学生类的中设置类型为List<成绩>的参数。从而达到,我获取到了一名学生的信息,同时我获取到了一个list,里面放的是这个学生的所有成绩信息。
多对多
其实现实生活中多对多的例子并不多,但我感觉有时候寻思着就把自己带坑里去了,这样来想:学生和课程。一名学生有多门课程,同时一门课程有很多学生去学。这里直接建立联系就很尴尬!
推荐一个方式,建立中间的表。这个表中可以存放学生学号,课程编号,和此学生这门课程的其他信息,比如说老师或者成绩,当然这都是后话了,只需要看这个例子就好。(本人在POJO中把其他无关的地方省略了)
三个POJO:
public class Student {
private StudentSelfcard studentSelfcard; //学生证类在学生类其中
private List<StudentLecture> studentLectureList;
...其他参数...
......getter and setter方法......
}
public class Lecture {
private List<StudentLecture> studentLectureList;
...其他参数...
......getter and setter方法......
}
public class StudentLecture {
private Lecture lecture;
private Student student;
...其他参数...
......getter and setter方法......
}
三个Mapper.xml,这里就不客气的全粘了:
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.cream.dao.StudentDao">
<resultMap id="studentMap" type="com.cream.pojo.Student">
<id property="studentId" column="student_id"/>
<result property="cnname" column="cnname"/>
<result property="sex" column="sex"/>
<result property="note" column="note"/>
<association property="studentSelfcard" column="student_id"
select="com.cream.dao.StudentSelfcardDao.findStudentSelfcardByStudentId"/>
<collection property="studentLectureList" column="student_id"
select="com.cream.dao.StudentLectureDao.findStudentLectureByStuId"/>
</resultMap>
<select id="getStudent" parameterType="int" resultMap="studentMap">
SELECT student_id,cnname,sex,note FROM t_student WHERE student_id = #{studentId }
</select>
</mapper>
LectureMapper.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.cream.dao.LectureDao">
<resultMap id="LectureMap" type="com.cream.pojo.Lecture">
<id property="courseId" column="course_id"/>
<result property="lectureName" column="lecture_name"/>
<result property="note" column="note"/>
<collection property="studentLectureList" column="lecture_id"
select="com.cream.dao.StudentLectureDao.findStudentLectureByLecId"/>
</resultMap>
<select id="getLecture" resultMap="LectureMap">
SELECT lecture_id,lecture_name,note FROM t_lecture WHERE lecture_id = #{lectureId }
</select>
</mapper>
StudentLectureMapper.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.cream.dao.StudentLectureDao">
<resultMap id="studentLectureMap" type="com.cream.pojo.StudentLecture">
<id property="id" column="id"/>
<result property="studentId" column="student_id"/>
<result property="lectureId" column="lecture_id"/>
<result property="grade" column="grade"/>
<result property="note" column="note"/>
<association property="lecture" column="lecture_id"
select="com.cream.dao.LectureDao.getLecture"/>
<association property="student" column="student_id"
select="com.cream.dao.StudentDao.getStudent"/>
</resultMap>
<select id="findStudentLectureByStuId" parameterType="int" resultMap="studentLectureMap">
SELECT id,student_id,lecture_id,grade,note FROM t_student_lecture WHERE student_id = #{studentId }
</select>
<select id="findStudentLectureByLecId" parameterType="int" resultMap="studentLectureMap">
SELECT id,student_id,lecture_id,grade,note FROM t_student_lecture WHERE lecture_id = #{LectureId }
</select>
</mapper>
然后通过main来测试
当我们获取到一名学生的时候,同时获得了他的一堆学生课程,通过学生课程们,再一一对应各门课。
当我们获取某一门课的时候,同时获得了这门课的一堆学生课程,通过学生课程们,再一一对应各位学生。
自此结束
总结一下这篇文章:
写的有些凌乱,很多地方自己都快绕蒙了。我的数据库能力真的很生涩。在设计表与表之间的关系思路上也是十分不成熟的。这篇自认为写的也比较一般。希望自己能够在练习中提高。
网友评论