使用Mybatis实现关联查询,分为一对一和一对多两种情况,最后并对ResultMap进行一个简要说明。
创建教师表,班级表,学生表,
假设一个老师只负责教一个班,那么老师和班级之间的关系是一对一的关系。
假设一个班级有多个学生,那么班级和学生之间的关系是一对多的关系。
CREATE TABLE teacher( t_id number(5) PRIMARY KEY, t_name VARCHAR2(20) ); CREATE TABLE class( c_id number(5) PRIMARY KEY , c_name VARCHAR2(20), teacher_id number(5) references teacher(t_id) ); --创建序列 create sequence teacher_seq; create sequence class_seq; INSERT INTO teacher VALUES(teacher_seq.nextval,'mike'); INSERT INTO teacher VALUES(teacher_seq.nextval,'john'); INSERT INTO class VALUES(class_seq.nextval,'Java10', 1); INSERT INTO class VALUES(class_seq.nextval,'Java11', 2); commit; select * from teacher; select *from class; select * from teacher t,class s where t.t_id = s.teacher_id and s.c_id=1 --学生表 CREATE TABLE student( s_id number(5) PRIMARY KEY , s_name VARCHAR2(20), class_id number(5) ); create sequence student_seq;--序列 --FK alter table student add constraint fk_cid foreign key(class_id) references class(c_id) INSERT INTO student VALUES(student_seq.nextval,'zhangsan', 1); INSERT INTO student VALUES(student_seq.nextval,'wangwu', 1); INSERT INTO student VALUES(student_seq.nextval,'liufei', 1); INSERT INTO student VALUES(student_seq.nextval,'cuihua', 2); INSERT INTO student VALUES(student_seq.nextval,'zhangfei', 2); INSERT INTO student VALUES(student_seq.nextval,'xionger', 2); select * from student; --查询某一个班级的老师,学生信息 SELECT * FROM class c, teacher t,student s where c.c_id = s.class_id and t.t_id=c.teacher_id and c.c_id=1
package com.hlx.entity; import java.util.List; /** * Classes 班级表 * * 一个班级有多个学生 * * @author Administrator * */ public class Classes { private int id; // c_id private String name; // c_name /** * class表中有一个teacher_id字段,所以在Classes类中定义一个teacher属性, * 用于维护teacher和class之间的一对一关系,通过这个teacher属性就可以知道这个班级是由哪个老师负责的 */ private Teacher teacher;// //使用一个List<Student>集合属性表示班级拥有的学生 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 Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } public Classes(int id, String name, Teacher teacher) { super(); this.id = id; this.name = name; this.teacher = teacher; } public Classes(int id) { super(); this.id = id; } public Classes() { super(); } @Override public String toString() { return "Classes [id=" + id + ", name=" + name + ", teacher=" + teacher + "]"; } }
package com.hlx.entity; /** * teachar 老师类 * @author Administrator * */ public class Teacher { private int id; // t_id private String name; // t_name 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 Teacher(int id, String name) { super(); this.id = id; this.name = name; } public Teacher(int id) { super(); this.id = id; } @Override public String toString() { return "Teacher [id=" + id + ", name=" + name + "]"; } public Teacher() { super(); } }
<?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.hlx.mapping.ClassesMapper"> <!-- 根据班级id查询班级信息(带老师的信息) ##1. 联表查询: select * from teacher t,class s where t.t_id = s.teacher_id and s.c_id=1 --> <select id="getClass" parameterType="int" resultMap="classMap"> select * from class s, teacher t where t.t_id = s.teacher_id and s.c_id=#{id} </select> <!-- 使用resultMap映射实体类和字段之间的一一对应关系 type:实体类类型; id:名称--> <resultMap type="com.hlx.entity.Classes" id="classMap"> <id property="id" column="c_id"/> <!-- pk --> <result property="name" column="c_name"/> <!-- column --> <!-- association 关联老师类--> <association property="teacher" javaType="com.hlx.entity.Teacher"> <id property="id" column="t_id"/> <result property="name" column="t_name"/> </association> </resultMap> <!-- ##2 执行两次查询 SELECT * FROM class WHERE c_id=1; //teacher_id=1 SELECT * FROM teacher WHERE t_id=1;//使用上面得到的teacher_id --> <select id="getClass2" parameterType="int" resultMap="ClassMap2"> select * from class where c_id=#{id} </select> <!--(2)使用resultMap映射实体类和字段之间的一一对应关系 --> <resultMap type="com.hlx.entity.Classes" id="ClassMap2"> <id property="id" column="c_id"/> <result property="name" column="c_name"/> <!-- teacher关联字段 --> <association property="teacher" column="teacher_id" select="getTeacher"/> </resultMap> <!--(3)老师的sql语句 ;必须对应相应的字段 --> <select id="getTeacher" parameterType="int" resultType="Teacher"> select t_id id,t_name name from teacher where t_id=#{id} </select> </mapper>
<!-- 将mapper文件加入到配置文件中 --> <mappers> <mapper resource="com/hlx/mapping/ClassesMapper.xml"/> </mappers>
package com.hlx.test; import java.io.InputStream; 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.apache.log4j.Logger; import org.junit.Test; import com.hlx.entity.Classes; import com.hlx.util.MyBatisUtil; /** * 测试类 *s * * @author Administrator * */ public class ClassesTest { // 日志对象 private Logger logger = Logger.getLogger(ClassesTest.class); /** * Classes [id=2, name=Java11, teacher=Teacher [id=2, name=john]] */ @Test public void getId() { SqlSession session = null; try { // 获得会话 session = MyBatisUtil.getSqlSession(true); // 映射sql的标识字符串 String statement = "com.hlx.mapping.ClassesMapper.getClass"; // 执行插入操作 Classes userinfos = session.selectOne(statement, 2); logger.debug("查询数据!"); System.out.println(userinfos); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { session.close(); // 对应一次数据库会话,会话结束必须关闭 } } /** * Classes [id=1, name=Java10, teacher=Teacher [id=1, name=mike]] */ @Test public void getId2() { SqlSession session = null; try { // 获得会话 session = MyBatisUtil.getSqlSession(true); // 映射sql的标识字符串 String statement = "com.hlx.mapping.ClassesMapper.getClass2"; // 执行插入操作 Classes userinfos = session.selectOne(statement, 1); logger.debug("查询数据!"); System.out.println(userinfos); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { session.close(); // 对应一次数据库会话,会话结束必须关闭 } } }
package com.hlx.entity; import java.util.List; /** * Classes 班级表 * * 一个班级有多个学生 * * @author Administrator * */ public class Classes { private int id; // c_id private String name; // c_name /** * class表中有一个teacher_id字段,所以在Classes类中定义一个teacher属性, * 用于维护teacher和class之间的一对一关系,通过这个teacher属性就可以知道这个班级是由哪个老师负责的 */ private Teacher teacher;// //使用一个List<Student>集合属性表示班级拥有的学生 private List<Student> students; public List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } 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 Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } public Classes(int id, String name, Teacher teacher) { super(); this.id = id; this.name = name; this.teacher = teacher; } public Classes(int id) { super(); this.id = id; } public Classes() { super(); } @Override public String toString() { return "Classes [id=" + id + ", name=" + name + ", teacher=" + teacher + ", students=" + students + "]"; } //注意添加学生集合后,必须重新生成写入 }
package com.hlx.entity; /** * 学生类 * @author Administrator * */ public class Student { private int id; // s_id private String name; // s_name 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 Student(int id, String name) { super(); this.id = id; this.name = name; } public Student() { super(); } public Student(int id) { super(); this.id = id; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + "]"; } }
<!-- OneToMany 方式一: 嵌套结果: 使用嵌套结果映射来处理重复的联合结果的子集 SELECT * FROM class c, teacher t,student s where c.c_id = s.class_id and t.t_id=c.teacher_id and c.c_id=1 --> <select id="getOneToMany" parameterType="int" resultMap="ClassMap3"> select * from class c, teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id} </select> <resultMap type="com.hlx.entity.Classes" id="ClassMap3"> <id property="id" column="c_id"/> <result property="name" column="c_name"/> <!-- 关联老师 --> <association property="teacher" column="teacher_id" javaType="com.hlx.entity.Teacher"> <id property="id" column="t_id"/> <result property="name" column="t_name"/> </association> <!-- ofType指定students集合中的对象类型 --> <collection property="students" ofType="com.hlx.entity.Student"> <id property="id" column="s_id"/> <result property="name" column="s_name"/> </collection> </resultMap> <!-- OneToMany 方式二: 嵌套查询:通过执行另外一个SQL映射语句来返回预期的复杂类型 select * from class where c_id=1 //通过c_id=1 select * from teacher where t_id=1 //上一个查询获得teacher_id的值 select * from student where class_id=1 //上一个查询得到的c_id的值 --> <select id="getOneToMany2" parameterType="int" resultMap="ClassMap4"> select * from class where c_id=#{id} </select> <resultMap type="com.hlx.entity.Classes" id="ClassMap4"> <id property="id" column="c_id"/> <result property="name" column="c_name"/> <!-- 关联teacher FK column="teacher_id"--> <association property="teacher" column="teacher_id" select="getTeacher2"/> <!-- 集合student FK column="c_id" --> <collection property="students" ofType="com.hlx.entity.Student" column="c_id" select="getStudent"/> </resultMap> <!-- teacher --> <select id="getTeacher2" parameterType="int" resultType="Teacher"> select t_id id,t_name name from teacher where t_id=#{id} </select> <!-- student --> <select id="getStudent" parameterType="int" resultType="Student"> select s_id id,s_name name from student where class_id=#{id} </select>
/** * Classes [id=2, name=Java11, teacher=Teacher [id=2, name=john], students=[Student [id=4, name=cuihua], Student [id=5, name=zhangfei], Student [id=6, name=xionger]]] */ @Test public void getOneToMany1() { SqlSession session = null; try { // 获得会话 session = MyBatisUtil.getSqlSession(true); // 映射sql的标识字符串 String statement = "com.hlx.mapping.ClassesMapper.getOneToMany"; // 执行插入操作 Classes userinfos = session.selectOne(statement, 2); logger.debug("查询数据!"); System.out.println(userinfos); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { session.close(); // 对应一次数据库会话,会话结束必须关闭 } } /** * * Classes [id=1, name=Java10, teacher=Teacher [id=1, name=mike], students=[Student [id=1, name=zhangsan], Student [id=2, name=wangwu], Student [id=3, name=liufei]]] * */ @Test public void getOneToMany2() { SqlSession session = null; try { // 获得会话 session = MyBatisUtil.getSqlSession(true); // 映射sql的标识字符串 String statement = "com.hlx.mapping.ClassesMapper.getOneToMany2"; // 执行插入操作 Classes userinfos = session.selectOne(statement, 1); logger.debug("查询数据!"); System.out.println(userinfos); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { session.close(); // 对应一次数据库会话,会话结束必须关闭 } }
2
3
4
5
6
7
8
|
1. cache – 配置给定模式的缓存
2. cache-ref – 从别的模式中引用一个缓存
3. resultMap – 这是最复杂而却强大的一个元素了,它描述如何从结果集中加载对象
4. sql – 一个可以被其他语句复用的SQL 块
5.
insert
– 映射
INSERT
语句
6.
update
– 映射
UPDATE
语句
7.
delete
– 映射DELEETE 语句
8.
select
- 映射
SELECT
语句
|
|
1. constructor – 用来将结果反射给一个实例化好的类的构造器
a) idArg – ID 参数;将结果集标记为ID,以方便全局调用
b) arg –反射到构造器的通常结果
2. id – ID 结果,将结果集标记为ID,以方便全局调用
3. result – 反射到JavaBean 属性的普通结果
4. association – 复杂类型的结合;多个结果合成的类型
a) nested result mappings – 几resultMap 自身嵌套关联,也可以引用到一个其它上
5. collection –复杂类型集合a collection
of
complex types
6. nested result mappings – resultMap 的集合,也可以引用到一个其它上
7. discriminator – 使用一个结果值以决定使用哪个resultMap
a)
case
– 基本一些值的结果映射的
case
情形
i. nested result mappings –一个
case
情形本身就是一个结果映射,因此也可以包括一些相同的元素,也可以引用一个外部resultMap。