2017 06 18
多对一和一对多关系的查询应用
多对一
关联表查询:
提出需求:
以学生和班级为例 :
站在学生的角度上 多对一的关系 N......1
站在班级的角度上 一对多的关系 1......N
因此如果学生和班级分成两张表 需要将两张表进行关系关联
在关系型数据库中可以采取的方式:
1.逻辑关联:
并不利用数据库提供的工具对表与表之间进行操作
程序编写人员在程序内对两个表的内容进行操作 通过代码进行联系的建立
方便数据迁移 开发使用的第一选择
2.物理关联:
利用外键形式进行数据的关联
通过这种方式完成多对一的表示 外键永远在多的一方
采取物理关联 需要进行外键设置 如下图:
那么 在java当中怎么来表示多对一的关系呢?
同样的逻辑 在 “多” 的一方 建立 “一” 的一方的对象属性
现在要查询学生信息并带回班级信息(class_name)
假设给定学生ID(studeny_id)
需要新建ClassInFo.java文件和Student.java文件
新建 Studentmapper.xml 和 ClassInFomapper.xml文件
更改主配置文件 mybatis-config.xml 和 log4j.properties
Studenmapper.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.shxt.model.Student">
<resultMap type="Student" id="BaseResultMapperStudent">
<id column="student_id" property="student_id" />
<result column="student_name" property="student_name" />
<result column="sex" property="sex" />
</resultMap>
</mapper>
ClassInFomapper.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.shxt.model.ClassInfo">
<resultMap type="ClassInfo" id="BaseResultMapperClassInFo">
<id column="class_id" property="class_id" />
<result column="class_name" property="class_name" />
</resultMap>
</mapper>
mybatis-config.xml文件添加mapper映射文件的引用路径
<mappers>
<mapper resource="com/shxt/model/StudentMapper.xml"/>
<mapper resource="com/shxt/model/ClassInFoMapper.xml"/>
</mappers>
log4j.properties属性文件内添加sql语句显示所必需的命名空间
log4j.logger.com.shxt.model.Student=TRACE
log4j.logger.com.shxt.model.ClassInFo=TRACE
为了能够保存查询出来的Class的ID 需要在Student.java类中新增一个属性 并在Studentmapper.xml中表明
Student.java :
private Integer class_id;
public Integer getClass_id() {
return this.class_id;
}
public void setClass_id( Integer class_id ) {
this.class_id = class_id;
}
Studentmapper.xml :
<resultMap type="Student" id="BaseResultMapperStudent">
<id column="student_id" property="student_id" />
<result column="student_name" property="student_name" />
<result column="sex" property="sex" />
<result column="class_id" property="class_id" />
</resultMap>
传统方式:
mapper映射文件语句示例:
Studentmapper.xml
<sql id="student_base_columns">
student_id,student_name,sex,user_name
</sql>
<select id="select01" parameterType="_int" resultMap="BaseResultMapperStudent">
SELECT
<include refid="student_base_columns"/>
FROM
student
WHERE
student_Id=#{student_id}
</select>
ClassInFomapper.xml
<sql id="ClassInFo_base_columns">
class_id,class_name
</sql>
<select id="get01" parameterType="_int" resultMap="BaseResultMapperClassInFo">
SELECT
<include refid="class_base_columns"/>
FROM
classinfo
WHERE
class_Id=#{class_id}
</select>
测试用例书写:
@Test
public void tesMethod01(){
SqlSession sqlsession = null;
try {
sqlsession = MyBatisUtils.getSqlSession();
//首先进行查询 拿到下一步查询必须的class_id
Student student = sqlsession.selectOne(Student.class.getName()+".select01",1);
//进行判断 利用class_id进行班级信息的查询
if(student.getClass_id()!=null){
ClassInFo classInFo = sqlsession.selectOne(Class.class.getName()+".get01",student.getClass_id());
//将查询出来的classInFo对象添加到student对象中
student.setClassInFo(classInFo);
}
//调用toString()进行输出
System.out.println(student);
} finally {
MyBatisUtils.closeSqlSession(sqlsession);
}
}
select方式:
Studentmapper.xml:
<resultMap type="Student" id="BaseResultMapperStudent">
<id column="student_id" property="student_id" />
<result column="student_name" property="student_name" />
<result column="sex" property="sex" />
<result column="class_id" property="class_id" />
<association property="calssInFo" javaType="ClassInFo" column="class_id" select="com.shxt.model.ClassInFo.get01"/>
<!-- <association> 关联对象的标签 property 属性名 javaType 这里因为是自定义类 所以采用别名方式 column建立联系的字段名(关键) select 去执行哪个命名空间的哪条语句(定位)-->
</resultMap>
<select id="select01" parameterType="_int" resultMap="BaseResultMapperStudent">
SELECT
<include refid="student_base_columns"/>
FROM
student
WHERE
student_Id=#{student_id}
</select>
测试用例书写:
@Test
public void tesMethod02(){
SqlSession sqlsession = null;
try {
sqlsession = MyBatisUtils.getSqlSession();
Student student = sqlsession.selectOne(Student.class.getName()+".select01",1);
System.out.println(student);
} finally {
MyBatisUtils.closeSqlSession(sqlsession);
}
}
如果编写完成select方式 再用传统方式查询相同sql语句 将会产生三条查询语句(第一次执行之后 会因为缓存原因 log4j显示两条语句)
对此 mybatis提供了<resultMap>标签的继承 使用extends属性 将内置对象与关联对象分离 按照需求 如果需要用到关联对象 就调用集成后的<resultMap>标签
代码示例:
Studentmapper.xml
<resultMap type="Student" id="BaseResultMapperStudent">
<id column="student_id" property="student_id" />
<result column="student_name" property="student_name" />
<result column="sex" property="sex" />
<result column="class_id" property="class_id" />
</resultMap>
<resultMap type="Student" id="BaseResultMapperStudentByObject" extends="BaseResultMapperStudent">
<association property="calssInFo" javaType="ClassInFo" column="class_id" select="com.shxt.model.ClassInFo.get01"/>
</resultMap>
连接查询方式:
mapper映射文件添加如下内容:
使用左外链接的方式 其实也可以进行两个表的查询,例如
SELECT * FROM class c,teacher t WHERE c.teacher_id=t.t_id AND c.c_id=1;
(这个语句我瞎写的 —— . —— )
测试代码示例:
@Test
public void tesMethod03(){
SqlSession sqlsession = null;
try {
sqlsession = MyBatisUtils.getSqlSession();
Student student = sqlsession.selectOne(Student.class.getName()+".query",1);
System.out.println(student);
} finally {
MyBatisUtils.closeSqlSession(sqlsession);
}
}
如果想进行多条记录的查询
需要将mapper文件中的where条件子句删掉
在测试用例中使用selectlist方法查询
返回List<Object>类型的值 再进行下一步处理
简单扩展 DTO POJO VO BO PO
同样的实体化类 处在不同的思想和场景下 针对于不同的目的 就有了这些名词的区别
一对多
依然以上述为例
上文介绍站在学生角度看的“多对一”关系的处理
现在尝试站在教室角度 来解决“一对多”关系的处理
在上文中 我们进行的实例化 仅仅是针对于学生和教室来做的
多个学生对象可以对应一个教室对象
我们需要在学生的持久化对象内建立教室对象的id属性 在数据库中建立主键联系 进而运用DTO对象或者select方式 连接查询方式来拿到教室对象的详细内容
现在我们转换思路 将“多对一”转化为“一对多”
首先需要在class持久化对象内建立student对象
但是由于是“一对多”关系 一个class对象会对应多个student对象 我们需要创建一个List<Student>类型的对象来进行查询结果的存储
同样在sudent实体化类中 依然存在 class_id 属性 依然可以进行一对一的查询
可以使用<collection>标签来进行“一对多”关系的查询处理
<resultMap type="ClassInfo" id="simple01" extends="BaseResultMapper">
<!-- collection标签
property指代类中属性名 在这里代表类中的studentList集合
javaType可以忽略不写让Mybatis来进行自动处理也可简写为list
ofType在集合中存的是什么类型
column指代用哪个字段进行下一步查询
select用来进行定位下一步动作的命名空间内的sql语句
-->
<collection property="studentList" javaType="java.util.List" ofType="Student"
column="class_id" select="com.shxt.model.Student.select01"/>
</resultMap>
在两个映射文件中的代码如下图所示
重点是<collection>标签的运用
在测试文件中测试用例的书写为一般测试格式
故不予示范