目录
引入
在此之前,我们的实体类的属性名跟数据库的表中的字段名是一致的,如下图。在写mapper.xml映射文件的时候,可以直接将字段名自动映射到对应的属性名。
但实际上字段名要符合数据库的规则,使用_,实体类中的属性名要符合Java规则,使用驼峰,例如学生的学号,字段名对应的是stu_id,属性名对应的是stuId,这样的话字段名和实体类中的属性名不一致,无法自动映射,这个时候那些字段名和属性名不一致的属性查询出来的结果就是没有值或者是默认值,那就需要我们自己处理它们之间的映射关系。
先设置两个实体类:Student和Clazz
字段名和属性名不一致的解决方法
我们自己手动处理映射关系有三种方式:起别名、设置全局配置和使用resultMap。
方式一:起别名
通过为字段起别名的方式,保证和实体类中的属性名保持一致。这样就可以像之前一样查询信息了。
<select id=”getAllStudentOld” resultType=”Student”>
select stu_id stuId,stu_name stuName,age,sex from t_student
</select>
方式二:设置全局配置
在MtBatis核心配置文件中设置:
<settings>
<setting name=”mapUnderscoreToCamelCase” value=”true”/>
</settings>
这样就可以在查询表中数据时,自动将_类型的字段名转换为驼峰。例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为userName。
方式三:使用resultMap
resultMap标签就是用来设置自定义的映射关系的标签,通常处理多对一和一对多的关系。有两个重要属性:id和type。id属性的值是resultMap标签的唯一标识,不可以重复,type属性用来设置映射关系中实体类类型。
子标签
id标签:设置主键的映射关系
result标签:这种普通字段的映射关系
association标签:设置多对一的映射关系
collection标签:设置一对多的映射关系
association标签和collection标签中也有id标签和result标签
子标签中的属性:
property:设置映射关系中实体类中的属性名,必须是type属性所设置的实体类类型中的属性名
column:设置映射关系中表中的字段名,必须是sql语句查询出的字段名
设置好resultMap标签后,要在select标签中的resultMap属性设置我们自己写的resultMap标签的id。标识我们使用了resultMap标签自定义了映射关系。方法一和方法二中还是使用的自动映射关系,所以select标签中的设置的是resultType,值为查询结果的类型
例如:
<resultMap id="stuResultMap" type="Student">
<id property="stuId" column="stu_id"></id>
<result property="stuName" column="stu_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
</resultMap>
<!--List<Student> getAllStudent();-->
<select id="getAllStudent" resultMap="stuResultMap">
select * from t_student
</select>
结果:
类中有类属性时的解决方法
上面我们解决了字段名和属性名不一致的问题,但是我们的实体类中不止有基本数据类型 的属性,还会有类类型的属性,比如学生类中有一个班级类的属性,里面有班级的id和班级的名字,班级中也有学生类的属性,里面是学生的信息。
而我们通过sql语句查询出来的信息是字段,班级id和名字或者学生的信息都是一堆字段,并不能直接将该字段直接对应到类属性中的属性,例如,我要查询一个学生的信息:学生的班级id查出来是class_id=1,字段名是用来对应属性名的。但是我的学生类中没有classId这个属性,这个属性是在学生类的stuClass这个类属性中的。或者我要查询班级的信息,班级中的学生id、姓名等等的信息查询出来也是一些字段名,Clazz类中也没有这些属性,这些属性是在students这个类属性中。这种情况又要怎么做呢。
前面也有讲到resultMap标签通常是用来处理多对一关系和一对多关系的,就是解决上面那种情况的。
两个重要子标签:
association标签:设置多对一的映射关系,多的那边添加一的对象,例如学生类中的班级类属性(多个学生对应一个班级),这个是站在多的角度。
collection标签:设置一对多的映射关系,一的那边添加多的集合,例如:班级类中的学生类属性(一个班级中有多个学生),这个是站在一的角度。
多对一映射关系处理
学生类
下面来查询学生信息
方法一:级联
通过类属性.类属性中的属性名来为property属性赋值
代码:
<!--Student getStudentAndClass(@Param("stuId") int stuId);-->
<!--处理多对一映射关系方式一:级联属性赋值-->
<resultMap id="studentAndClassResultMap1" type="Student">
<id property="stuId" column="stu_id"></id>
<result property="stuName" column="stu_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="stuClass.classId" column="class_id"></result>
<result property="stuClass.className" column="class_name"></result>
</resultMap>
<!--学生实体中有其班级信息的实体成员,查询出来的信息只能是班级id和班级名称,无法与其对应起来,所以用resultMap-->
<select id="getStudentAndClass" resultMap="studentAndClassResultMap1">
select * from t_student left join t_class on t_class.class_id = t_student.class_id where t_student.stu_id = #{stuId}
</select>
方法二:使用association标签
association标签中的属性:
property:需要处理多对一映射关系的属性名,本例中就是学生类中的类属性——stuClass
javaType:该属性的类型,本例中就是stuClass这个类属性的类型——Clazz。
association标签中的子标签:id和result,用法跟之前一样。
id标签:设置主键的映射关系
result标签:这种普通字段的映射关系。
子标签中的属性:
property:设置映射关系中实体类中的属性名,必须是type属性所设置的实体类类型中的属性名
column:设置映射关系中表中的字段名,必须是sql语句查询出的字段名。
例如:
<!--Student getStudentAndClass2(@Param("stuId") int stuId);-->
<!--处理多对一映射关系方式二:association-->
<resultMap id="studentAndClassResultMap2" type="Student">
<id property="stuId" column="stu_id"></id>
<result property="stuName" column="stu_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<!--
association:处理多对一映射关系
property:需要处理多对一映射关系的属性名
javaType:该属性的类型
-->
<association property="stuClass" javaType="Clazz">
<id property="classId" column="class_id"></id>
<result property="className" column="class_name"></result>
</association>
</resultMap>
<select id="getStudentAndClass2" resultMap="studentAndClassResultMap2">
select * from t_student left join t_class on t_class.class_id = t_student.class_id where t_student.stu_id = #{stuId}
</select>
测试方法方法一一样
结果
方法三:分步查询
在association标签中有两个属性:select属性和column属性
select:设置分布查询第二步的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)。
column:设置分布查询第二步的条件,两个表相互关联的字段,就像是主键和外键的关系。
第一步先查询学生信息,在association标签中设置select属性和column属性。这样就可以通过select属性中的sql唯一标识定位第二步查询班级信息的sql语句,通过column中的值来确定第二步的查询条件,进而查到学生所对应的班级信息。
例如:
第一步:
在StudentMapper.xml文件中
<!--处理多对一映射关系方式三:分步查询-->
<!--第一步查询学生信息-->
<resultMap id="studentAndClassByStepResultMap1" type="Student">
<id property="stuId" column="stu_id"></id>
<result property="stuName" column="stu_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<!--
select:设置分布查询第二步的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
column:设置分布查询第二步的条件
property:要处理的实体中的多对一的属性
-->
<association property="stuClass"
select="mybatis.mappers.ClazzMapper.getStudentAndClassByStep2"
column="class_id">
</association>
</resultMap>
<select id="getStudentAndClassByStep1" resultMap="studentAndClassByStepResultMap1">
select * from t_student where stu_id = #{stuId}
</select>
在StudentMapper.java文件中:
第二步:
在ClazzMapper.xml文件中:
<!--Class getStudentAndClassByStep2(@Param("classId") int classId);-->
<!--用全局配置自动匹配字段名和属性名-->
<select id="getStudentAndClassByStep2" resultType="Clazz">
select * from t_class where class_id = #{classId}
</select>
在ClazzMapper.java文件中:
测试代码跟之前的类似:
多对一映射关系处理
班级类:
下面来查询班级信息:
方法一:使用collection标签
collection标签中的属性:
property:需要处理一对多映射关系的属性名,本例中就是班级类中的集合——students
ofType:该属性所在的集合中存储的数据的类型,本例中就是students这个集合中的数据的类型——Student。
collection标签中的子标签:id和result,用法跟之前一样。
id标签:设置主键的映射关系
result标签:这种普通字段的映射关系。
例如:
<!--Class getClassAndStudent(@Param("classId") int classId);-->
<resultMap id="classAndStudentResultMap" type="Clazz">
<id property="classId" column="class_id"></id>
<result property="className" column="class_name"></result>
<!--
collection:处理一对多映射关系
property:需要处理一对多映射关系的属性名
ofType:该属性所在的集合中存储的数据的类型
-->
<collection property="students" ofType="Student">
<id property="stuId" column="stu_id"></id>
<result property="stuName" column="stu_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
</collection>
</resultMap>
<select id="getClassAndStudent" resultMap="classAndStudentResultMap">
select *
from t_class left join t_student on t_class.class_id = t_student.class_id
where t_class.class_id = #{classId}
</select>
ClazzMapper.java文件中:
测试:
结果:
方法二:分步查询
在collection标签中有两个属性:select属性和column属性
select:设置分布查询第二步的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)。
column:设置分布查询第二步的条件,两个表相互关联的字段,就像是主键和外键的关系。
查询的思路跟步骤和多对一关系的一样
第一步
在ClazzMapper.xml文件中编写下面代码
<!--Clazz getClassAndStudentByStep1(@Param("classId")int classId);-->
<resultMap id="classAndStudentByStepResultMap" type="Clazz">
<id property="classId" column="class_id"></id>
<result property="className" column="class_name"></result>
<collection property="students"
select="mybatis.mappers.StudentMapper.getClassAndStudentByStep2"
column="class_id"
fetchType="eager">
</collection>
</resultMap>
<select id="getClassAndStudentByStep1" resultMap="classAndStudentByStepResultMap">
select * from t_class where class_id = #{classId}
</select>
在ClazzMapper.java中:
第二步:
在StudentMapper.xml中
<!--List<Student> getClassAndStudentByStep2(@Param("classId") int classId);-->
<!--通过分布查询来查询班级及其所有学生信息
第二步:根据班级id查询学生信息-->
<select id="getClassAndStudentByStep2" resultType="Student">
select * from t_student where class_id = #{classId}
</select>
StudentMapper.java
测试:
结果:
总结
表的字段名和实体类的属性名不一致的解决办法
1. 给字段名设置别名,保持与属性名的一致
2.在mybatis-config.xml文件中设置全局配置,将_自动映射为驼峰,但是字段名和属性名要符合规则
<setting name=”mapUnderscoreToCamelCase” value=”true”/>
3.使用resultMap设置自定义映射关系
处理多对一的映射关系:
1.级联属性赋值
2.association
3.分步查询
处理一对多的映射关系
1.collection
2.分步查询