前言
我们在实际开发中是不仅仅针对一张表,而是两张或者多张表联动的操作,这里我们经常面对的关系就是一对一,一对多,多对一,多对多等等。
这里我们搭建环境,我们看看最常见的数据关系,学生和老师的关系
- 对于老师来说,一个老师拥有多个学生
- 对于学生而言,多个学生都有一个老师
1 | create table teachers ( |
2 | `id` int(20) not null auto_increment, |
3 | `name` varchar(64) not null, |
4 | PRIMARY KEY (`id`) |
5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
6 | |
7 | insert into teachers (`name`) values ('燕子李三'); |
8 | |
9 | create table students ( |
10 | `id` int(20) not null auto_increment, |
11 | `name` varchar(64) not null, |
12 | `tid` int(20) not null, |
13 | PRIMARY KEY (`id`) |
14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; |
15 | |
16 | insert into students (`name`, `tid`) values ('张三', 1), ('李四', 1), ('王五', 1), ('赵六', 1); |
我们导入数据库,然后开始创建项目。
搭建新项目
到目前为之,我觉得学习就是一个重复的过程,不停的创建新的实验性项目,当然我心里也是很烦的。但是没有办法,发现只有动手之后我才能知道到底哪里有问题,我才能有针对性的记忆。这里我们建立一个 mybatis-06
创建好之后,我们在需要在 pom.xml
的 project
标签中加入以下代码:
第一步,pom.xml
加入相应的配置
1 | <!-- 在build中配置resource,来防止我们资源导出失败的问题 --> |
2 | <build> |
3 | <resources> |
4 | <resource> |
5 | <directory>src/main/resources</directory> |
6 | <includes> |
7 | <include>**/*.properties</include> |
8 | <include>**/*.xml</include> |
9 | </includes> |
10 | <filtering>true</filtering> |
11 | </resource> |
12 | |
13 | <resource> |
14 | <directory>src/main/java</directory> |
15 | <includes> |
16 | <include>**/*.properties</include> |
17 | <include>**/*.xml</include> |
18 | </includes> |
19 | <filtering>true</filtering> |
20 | </resource> |
21 | </resources> |
22 | </build> |
这个配置主要是为了相关的 XML 文件在编译之后,能被打包到对应的位置。
第二步:创建 db.properties
mybatis-config.xml
配置类
db.properties 配置如下:
1 | driver=com.mysql.jdbc.Driver |
2 | url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Hongkong |
3 | username=root |
4 | password= |
mybatis-config.xml 配置如下:
1 |
|
2 |
|
3 |
|
4 |
|
5 | |
6 | <configuration> |
7 | <properties resource="db.properties"/> |
8 | |
9 | <settings> |
10 | <setting name="logImpl" value="STDOUT_LOGGING"/> |
11 | </settings> |
12 | |
13 | <environments default="development"> |
14 | <environment id="development"> |
15 | <transactionManager type="JDBC"/> |
16 | <dataSource type="POOLED"> |
17 | <property name="driver" value="${driver}"/> |
18 | <property name="url" value="${url}"/> |
19 | <property name="username" value="${username}"/> |
20 | <property name="password" value="${password}"/> |
21 | </dataSource> |
22 | </environment> |
23 | </environments> |
24 | </configuration> |
第三步:创建 MybatisUtils 工具类
1 | package com.yubulang.utils; |
2 | |
3 | import org.apache.ibatis.io.Resources; |
4 | import org.apache.ibatis.session.SqlSession; |
5 | import org.apache.ibatis.session.SqlSessionFactory; |
6 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; |
7 | |
8 | import java.io.IOException; |
9 | import java.io.InputStream; |
10 | |
11 | public class MybatisUtils { |
12 | private static SqlSessionFactory sqlSessionFactory; |
13 | |
14 | static { |
15 | try { |
16 | String resource = "mybatis-config.xml"; |
17 | InputStream in = Resources.getResourceAsStream(resource); |
18 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); |
19 | } catch (IOException e) { |
20 | e.printStackTrace(); |
21 | } |
22 | } |
23 | |
24 | public static SqlSession getSqlSession() { |
25 | return sqlSessionFactory.openSession(); |
26 | } |
27 | } |
到这里我们已经有了一个基础的架子。
一对多
对于老师而言,一个老师负责多个学生,我们来创建两个实体类:
创建实体类
com.yubulang.pojo.Teacher.java
:
1 | package com.yubulang.pojo; |
2 | |
3 | public class Teacher { |
4 | private int id; |
5 | private String name; |
6 | |
7 | public Teacher() { |
8 | } |
9 | |
10 | public Teacher(int id, String name) { |
11 | this.id = id; |
12 | this.name = name; |
13 | } |
14 | |
15 | public int getId() { |
16 | return id; |
17 | } |
18 | |
19 | public void setId(int id) { |
20 | this.id = id; |
21 | } |
22 | |
23 | public String getName() { |
24 | return name; |
25 | } |
26 | |
27 | public void setName(String name) { |
28 | this.name = name; |
29 | } |
30 | |
31 | |
32 | public String toString() { |
33 | return "Teacher{" + |
34 | "id=" + id + |
35 | ", name='" + name + '\'' + |
36 | '}'; |
37 | } |
38 | } |
com.yubulang.pojo.Student
,注意这里我们要关联 Teacher,所以在 Student 的属性中 teacher 应该对应 Teacher 类:
1 | package com.yubulang.pojo; |
2 | |
3 | public class Student { |
4 | private int id; |
5 | private String name; |
6 | private Teacher teacher; |
7 | |
8 | public Student() { |
9 | } |
10 | |
11 | public Student(int id, String name, Teacher teacher) { |
12 | this.id = id; |
13 | this.name = name; |
14 | this.teacher = teacher; |
15 | } |
16 | |
17 | public int getId() { |
18 | return id; |
19 | } |
20 | |
21 | public void setId(int id) { |
22 | this.id = id; |
23 | } |
24 | |
25 | public String getName() { |
26 | return name; |
27 | } |
28 | |
29 | public void setName(String name) { |
30 | this.name = name; |
31 | } |
32 | |
33 | public Teacher getTeacher() { |
34 | return teacher; |
35 | } |
36 | |
37 | public void setTeacher(Teacher teacher) { |
38 | this.teacher = teacher; |
39 | } |
40 | |
41 | |
42 | public String toString() { |
43 | return "Student{" + |
44 | "id=" + id + |
45 | ", name='" + name + '\'' + |
46 | ", teacher=" + teacher + |
47 | '}'; |
48 | } |
49 | } |
创建实现接口
com.yubulang.dao.StudentMapper.java
, 因为关联方式有两种:
1 | package com.yubulang.dao; |
2 | |
3 | import com.yubulang.pojo.Student; |
4 | import com.yubulang.pojo.Teacher; |
5 | |
6 | import java.util.List; |
7 | |
8 | public interface StudentMapper { |
9 | |
10 | // 第一种方式 根据结果描述隐射关系 |
11 | List<Student> getStudent(); |
12 | |
13 | // 第二种方式 |
14 | List<Student> getStudentList(); |
15 | } |
有了实现接口,我们需要对应的 xml 与之匹配它的实现。我们把 xml 放到 resources/com/yubulang/dao
中,命名为 StudentMapper.xml
:
1 |
|
2 |
|
3 |
|
4 |
|
5 | |
6 | <mapper namespace="com.yubulang.dao.StudentMapper"> |
7 | <!-- 第一种方法,编写关联关系去查询 --> |
8 | <select id="getStudent" resultMap="StudentTeacher"> |
9 | select * from students; |
10 | </select> |
11 | |
12 | <resultMap id="StudentTeacher" type="Student"> |
13 | <association property="teacher" column="tid" javaType="Teacher" select="getTeacherByTid"/> |
14 | </resultMap> |
15 | |
16 | <select id="getTeacherByTid" resultType="Teacher"> |
17 | select * from teachers where id=#{id} |
18 | </select> |
19 | |
20 | <!-- 第二种方法(相对简单):根据查询结果来关联 --> |
21 | <select id="getStudentList" resultMap="StudentTeacher2"> |
22 | select s.id sid, s.name sname, t.id tid, t.name tname from students s, teachers t where s.tid = t.id; |
23 | </select> |
24 | |
25 | <resultMap id="StudentTeacher2" type="Student"> |
26 | <result property="id" column="sid"/> |
27 | <result property="name" column="sname"/> |
28 | <association property="teacher" javaType="Teacher"> |
29 | <result property="id" column="tid"/> |
30 | <result property="name" column="tname"/> |
31 | </association> |
32 | </resultMap> |
33 | </mapper> |
测试类的干活
1 | package com.yubulang.dao; |
2 | |
3 | import com.yubulang.pojo.Student; |
4 | import com.yubulang.utils.MybatisUtils; |
5 | import org.apache.ibatis.session.SqlSession; |
6 | import org.junit.Test; |
7 | |
8 | import java.util.List; |
9 | |
10 | public class StudentMapperTest { |
11 | |
12 | public void testGetStudent() { |
13 | SqlSession sqlSession = MybatisUtils.getSqlSession(); |
14 | StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); |
15 | List<Student> studentList = mapper.getStudent(); |
16 | for (Student student : studentList) { |
17 | System.out.println(student); |
18 | } |
19 | |
20 | sqlSession.close(); |
21 | } |
22 | |
23 | |
24 | public void testGetStudentList() { |
25 | SqlSession sqlSession = MybatisUtils.getSqlSession(); |
26 | StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); |
27 | List<Student> studentList = mapper.getStudentList(); |
28 | for (Student student : studentList) { |
29 | System.out.println(student); |
30 | } |
31 | |
32 | sqlSession.close(); |
33 | } |
34 | } |
多对一
对于学生而言,多个学生跟着一个老师,我们来创建两个实体类:
创建实体类
com.yubulang.pojo.Teacher
:
1 | package com.yubulang.pojo; |
2 | |
3 | import java.util.List; |
4 | |
5 | public class Teacher { |
6 | private int id; |
7 | private String name; |
8 | |
9 | // 一个老师有多个学生 |
10 | private List<Student> students; |
11 | |
12 | public Teacher() { |
13 | } |
14 | |
15 | public Teacher(int id, String name, List<Student> students) { |
16 | this.id = id; |
17 | this.name = name; |
18 | this.students = students; |
19 | } |
20 | |
21 | public int getId() { |
22 | return id; |
23 | } |
24 | |
25 | public void setId(int id) { |
26 | this.id = id; |
27 | } |
28 | |
29 | public String getName() { |
30 | return name; |
31 | } |
32 | |
33 | public void setName(String name) { |
34 | this.name = name; |
35 | } |
36 | |
37 | public List<Student> getStudents() { |
38 | return students; |
39 | } |
40 | |
41 | public void setStudents(List<Student> students) { |
42 | this.students = students; |
43 | } |
44 | |
45 | |
46 | public String toString() { |
47 | return "Teacher{" + |
48 | "id=" + id + |
49 | ", name='" + name + '\'' + |
50 | ", students=" + students + |
51 | '}'; |
52 | } |
53 | } |
com.yubulang.pojo.Student
:
1 | package com.yubulang.pojo; |
2 | |
3 | public class Student { |
4 | private int id; |
5 | private String name; |
6 | private int tid; |
7 | |
8 | public Student() { |
9 | } |
10 | |
11 | public Student(int id, String name, int tid) { |
12 | this.id = id; |
13 | this.name = name; |
14 | this.tid = tid; |
15 | } |
16 | |
17 | public int getId() { |
18 | return id; |
19 | } |
20 | |
21 | public void setId(int id) { |
22 | this.id = id; |
23 | } |
24 | |
25 | public String getName() { |
26 | return name; |
27 | } |
28 | |
29 | public void setName(String name) { |
30 | this.name = name; |
31 | } |
32 | |
33 | public int getTid() { |
34 | return tid; |
35 | } |
36 | |
37 | public void setTid(int tid) { |
38 | this.tid = tid; |
39 | } |
40 | |
41 | |
42 | public String toString() { |
43 | return "Student{" + |
44 | "id=" + id + |
45 | ", name='" + name + '\'' + |
46 | ", tid=" + tid + |
47 | '}'; |
48 | } |
49 | } |
创建实现接口
com.yubulang.dao.TeacherMapper
:
1 | package com.yubulang.dao; |
2 | |
3 | import com.yubulang.pojo.Teacher; |
4 | import org.apache.ibatis.annotations.Param; |
5 | |
6 | public interface TeacherMapper { |
7 | Teacher getTeacherById(@Param("tid") int id); |
8 | |
9 | Teacher getTeacherByIdAnother(@Param("tid") int id); |
10 | } |
有了实现接口,我们需要对应的 xml 与之匹配它的实现。我们把 xml 放到 resources/com/yubulang/dao
中,命名为 TeacherMapper.xml
:
1 |
|
2 |
|
3 |
|
4 |
|
5 | |
6 | <mapper namespace="com.yubulang.dao.TeacherMapper"> |
7 | <!--第一种方式(复杂度在sql)--> |
8 | <select id="getTeacherById" resultMap="TeacherStudent"> |
9 | select t.id tid, t.name tname, s.id sid, s.name sname |
10 | from teachers t, |
11 | students s |
12 | where t.id = s.tid |
13 | and t.id = #{tid}; |
14 | </select> |
15 | |
16 | <resultMap id="TeacherStudent" type="Teacher"> |
17 | <result property="id" column="tid"/> |
18 | <result property="name" column="tname"/> |
19 | <collection property="students" ofType="Student"> |
20 | <result property="id" column="sid"/> |
21 | <result property="name" column="sname"/> |
22 | <result property="tid" column="tid"/> |
23 | </collection> |
24 | </resultMap> |
25 | |
26 | <!--第二种方式复杂度在凭借--> |
27 | <select id="getTeacherByIdAnother" resultMap="TeacherStudentAnother"> |
28 | select id, name |
29 | from teachers |
30 | where id = #{tid} |
31 | </select> |
32 | |
33 | <resultMap id="TeacherStudentAnother" type="Teacher"> |
34 | <result property="id" column="id"/> |
35 | <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTid" column="id"> |
36 | <result property="id" column="id"/> |
37 | <result property="name" column="name"/> |
38 | <result property="tid" column="tid"/> |
39 | </collection> |
40 | </resultMap> |
41 | |
42 | <select id="getStudentByTid" resultType="Student"> |
43 | select * |
44 | from students |
45 | where tid = #{tid} |
46 | </select> |
47 | </mapper> |
测试代码的干货
1 | package com.yubulang.dao; |
2 | |
3 | import com.yubulang.pojo.Teacher; |
4 | import com.yubulang.utils.MybatisUtils; |
5 | import org.apache.ibatis.session.SqlSession; |
6 | import org.junit.Test; |
7 | |
8 | public class TeacherMapperTest { |
9 | |
10 | public void testGetTeacherById() { |
11 | SqlSession sqlSession = MybatisUtils.getSqlSession(); |
12 | |
13 | TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class); |
14 | Teacher teacherById = mapper.getTeacherById(1); |
15 | |
16 | System.out.println(teacherById); |
17 | |
18 | sqlSession.close(); |
19 | } |
20 | |
21 | |
22 | public void testGetTeacherByIdAnother() { |
23 | SqlSession sqlSession = MybatisUtils.getSqlSession(); |
24 | |
25 | TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class); |
26 | Teacher teacherById = mapper.getTeacherByIdAnother(1); |
27 | |
28 | System.out.println(teacherById); |
29 | |
30 | sqlSession.close(); |
31 | } |
32 | } |
总结
比之前更发杂了点,但是这些关系是我们做项目时常用的一些数组组成方式。有个基础,后面复杂的都不在话下。