关于mybatis环境的搭建,见mybatis环境搭建
关联查询就是多表查询,开发中用得很多
1. 创建数据库中的表和pojo类:
CREATE TABLE `students` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`name` varchar(30) DEFAULT NULL,
`sex` varchar(10) DEFAULT NULL,
`age` int(20) DEFAULT NULL,
`tel` varchar(15) DEFAULT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `article` (
`id` int(12) NOT NULL,
`title` varchar(20) DEFAULT NULL,
`content` varchar(30) DEFAULT NULL,
`student_id` int(12) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=gbk;
建立了两张表,一张是students,一张是article。一个学生可以写很多的文章,但一篇文章只能有一个学生作者。
因此,学生对于文章,是一对多的关系。文章对于学生来说,是一对一的关系。
两张表插入的数据如下:
对应的pojo类如下:
public class Student {
private Integer id;
private String name;
private String sex;
private Integer age;
private String tel;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", sex=" + sex
+ ", age=" + age + ", tel=" + tel + "]";
}
}
public class Article {
private Integer id;
private String title;
private String content;
private Integer student_id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getStudent_id() {
return student_id;
}
public void setStudent_id(Integer student_id) {
this.student_id = student_id;
}
@Override
public String toString() {
return "Article [id=" + id + ", title=" + title + ", content="
+ content + ", student_id=" + student_id + "]";
}
}
2.一对一查询
通过查询文章信息来查询学生信息,为一对一查询,因为一篇文章只对应一个学生。
一对一查询有两种方式。
2.1 方式一:新创建一个类来描述表结构
查询到的结果是一个类似于笛卡尔乘积的表结构,所以可以新建一个类,来描述这种表结构。
public class StudentArticle {
//字段为article中的字段
private Integer id;
private String title;
private String content;
private Integer student_id;
private String name;
private String sex;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
private String tel;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getStudent_id() {
return student_id;
}
public void setStudent_id(Integer student_id) {
this.student_id = student_id;
}
@Override
public String toString() {
return "StudentArticle [id=" + id + ", title=" + title + ", content="
+ content + ", student_id=" + student_id + ", name=" + name
+ ", sex=" + sex + ", age=" + age + ", tel=" + tel + "]";
}
}
这个类包括了Student,Article两个类的所有属性。
映射文件associationQuery .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">
<!-- namespace:命名空间,做sql隔离 ,访问sql语句时,sql的id前面要带着命名空间-->
<mapper namespace="assQuery">
<select id="findArticle" resultType="com.mq.pojo.StudentArticle">
SELECT
article.*,
students.name,
students.age
FROM
students,article
WHERE article.student_id = students.id
</select>
</mapper>
测试:
/**
* 联合查询,一对一
*/
@Test
public void assQuery(){
SqlSession openSession = factory.openSession();
List<StudentArticle> list=openSession.selectList("assQuery.findArticle");
System.out.println(list);
openSession.close();
}
结果:
[StudentArticle [id=1, title=学习java, content=内容-java, student_id=1, name=关羽, sex=null, age=42, tel=null], StudentArticle [id=3, title=学习物理, content=内容-物理, student_id=1, name=关羽, sex=null, age=42, tel=null], StudentArticle [id=2, title=数据库, content=内容-数据库, student_id=2, name=刘备, sex=null, age=41, tel=null], StudentArticle [id=3, title=数学, content=内容-数学, student_id=2, name=刘备, sex=null, age=41, tel=null]]
2.2 方式二:使用resultMap
使用resultMap,定义专门的resultMap用于映射一对一查询结果。
每一个Article对应一个Student,所以可以将Student设置为Article的一个属性。
修改后的Article(添加了Student 属性):
public class Article {
private Integer id;
private String title;
private String content;
private Integer student_id;
//添加了Student属性
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getStudent_id() {
return student_id;
}
public void setStudent_id(Integer student_id) {
this.student_id = student_id;
}
@Override
public String toString() {
return "Article [id=" + id + ", title=" + title + ", content="
+ content + ", student_id=" + student_id + ", student="
+ student + "]";
}
}
修改后的映射文件:
<?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">
<!-- namespace:命名空间,做sql隔离 ,访问sql语句时,sql的id前面要带着命名空间-->
<mapper namespace="assQuery">
<!-- type表示查询结果的类型 -->
<!--column表示数据库中的字段,property表示pojo类中的属性,通过这种方式将两种字段和属性关联起来 -->
<resultMap type="com.mq.pojo.Article" id="articleStudentMap">
<id column="id" property="id"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
<result column="student_id" property="student_id"/>
<!--如果属性不是基础数据类型,就需要用到association标签,javaType表示该属性的类型,该类的全路径名即可 -->
<association property="student" javaType="com.mq.pojo.Student">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="sex" property="sex"/>
<result column="age" property="age"/>
<result column="tel" property="tel"/>
</association>
</resultMap>
<select id="findArticle" resultMap="articleStudentMap">
SELECT
article.*,
students.name,
students.age
FROM
students,article
WHERE article.student_id = students.id
</select>
</mapper>
测试:
/**
* 联合查询,一对一
*/
@Test
public void testResultMap(){
SqlSession openSession = factory.openSession();
List<Article> list=openSession.selectList("assQuery.findArticle");
for (Article article : list) {
System.out.println("文章名称--"+article.getTitle()+" 作者是--"+article.getStudent().getName());
}
openSession.close();
}
结果:
文章名称--学习java 作者是--关羽
文章名称--学习物理 作者是--关羽
文章名称--数据库 作者是--刘备
文章名称--数学 作者是--刘备
3.一对多查询
查询一个学生写的所有文章,因为一个学生可以写多篇文章,所以为一对多。
修改学生的bean,因为一个学生可以有多篇文章,所以添加一个list属性。
public class Student {
private Integer id;
private String name;
private String sex;
private Integer age;
private String tel;
//学生可以发表多篇文章
private List<Article> list;
public List<Article> getList() {
return list;
}
public void setList(List<Article> list) {
this.list = list;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", sex=" + sex
+ ", age=" + age + ", tel=" + tel + "]";
}
}
因为是一对多,所以映射文件也需要修改。
修改后的文件如下:
<?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">
<!-- namespace:命名空间,做sql隔离 ,访问sql语句时,sql的id前面要带着命名空间-->
<mapper namespace="yiduiduo">
<!-- type表示查询结果的类型 -->
<!--column表示数据库中的字段,property表示pojo类中的属性,通过这种方式将两种字段和属性关联起来 -->
<resultMap type="com.mq.pojo.Student" id="articleStudentMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="sex" property="sex"/>
<result column="age" property="age"/>
<result column="tel" property="tel"/>
<!--collection表示该属性为一个集合,ofType表示该集合中的对象的类型 -->
<collection property="list" ofType="com.mq.pojo.Article">
<id column="a_id" property="id"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
<result column="student_id" property="student_id"/>
</collection>
</resultMap>
<select id="findStudent" resultMap="articleStudentMap">
SELECT
students.*,
article.title,
article.content,
article.id a_id
FROM
students left join article
on article.student_id = students.id
</select>
</mapper>
测试:
@Test
public void yiduiduo(){
SqlSession openSession = factory.openSession();
List<Student> list=openSession.selectList("yiduiduo.findStudent");
for (Student student : list) {
System.out.println(student.getName()+"写的文章个数是"+student.getList().size());
}
openSession.close();
}
一对多表查询注意事项:
两张表的查询结果一定不能出现相同的字段,如果有,需要使用别名加以区分;查询语句中的字段,在映射关系中一定要有。