0%

java之orm的MyBatis关系映射

说明

  • 本地环境:mysql 8.0,java 1.8,idea社区版本
  • 这篇文章 介绍了对Hibernate的关系映射的使用
  • 之前写过jsp+mybatis的文章,本次详细介绍mybatis的常见用法

依赖文件

  • pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>

一对一

  • 这篇文章 介绍了对Hibernate的关系映射

  • 直接用表t_idCard、t_person

  • 直接用Person、IdCard实体类

  • 创建db.properties文件,在resources目录下

1
2
3
4
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai
user=root
password=123456
  • 接下来就要创建一个xml文件作为MyBatis的核心配置文件了,src-main-resources-mybatis-config.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!--mybatis-config.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

<!--读取配置文件中的数据库连接信息-->
<properties resource="db.properties"/>
<settings>
<!--设置日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--开启驼峰命名,映射数据库到对象属性名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--开启缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>

<!--给实体类取别名,为了后面配置mapper.xml时不用写全限定名,方便使用-->
<typeAliases>
<!--包扫描-->
<package name="xyz.shi.entity"/>
</typeAliases>

<environments default="development">
<!--id属性必须和上面的default一样 -->
<environment id="development">
<transactionManager type="JDBC"/>
<!--dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象源 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 注册userMapper.xml文件 -->
<mapper resource="UserMapper.xml"/>
</mappers>

</configuration>
  • src-main-resources-personMapper.xml 新建如下person表的增删改查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?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="personMapper">
<!-- 定义封装person和IdCard的resultMap -->
<resultMap id="personIdCardMap" type="xyz.shi.domain.Person">
<id property="id" column="id"/>
<!--IdCard的id -->
<!-- <result property="t_idCard_id" column="t_idCard_id"/>-->
<result property="name" column="name"/>
<!-- association配置一对一关系,property为Person中属性名,javaType为属性类型 -->
<association property="idCard" javaType="xyz.shi.domain.IdCard">
<!-- column="t_idCard_id 对应person表中的t_idCard_id-->
<id property="id" column="t_idCard_id"/>
<result property="cardNo" column="cardNo"/>
</association>
</resultMap>
<!--配置查询所有-->
<select id="findAll" resultMap="personIdCardMap">
select p.name, p.id as pid, c.id as cid, c.cardNo from t_person p, t_idCard c where c.id = p.t_idCard_id
</select>
<!-- 通过id(唯一)获取用户-->
<select id="queryOne" parameterType="int" resultMap="personIdCardMap">
select p.name, p.id as pid, c.id as cid, c.cardNo from t_person p, t_idCard c where c.id = p.t_idCard_id and p.id=#{id}

</select>
<!-- 插入 -->
<insert id="insertPerson" parameterType="Person">
insert into t_person (name,t_idCard_id) values(#{name},#{idCard.id})
</insert>

<update id="modifyPerson" parameterType="Person">
update t_person set name=#{name},t_idCard_id=#{idCard.id} where id=#{id}
</update>
<!-- 根据 id 删除 -->
<delete id="deletePerson" parameterType="int">
delete from t_person where id=#{id}
</delete>
</mapper>
  • personDao
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package xyz.shi.dao;

import xyz.shi.domain.Person;

import java.util.List;

public interface PersonDao {
List<Person> findAll();
Person queryOne(int id);
int insert(Person person);
int modify(Person person);
int delete(int id);
}

  • 实现personDao接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package xyz.shi.dao.impl;

import org.apache.ibatis.session.SqlSession;
import xyz.shi.dao.PersonDao;
import xyz.shi.domain.Person;
import xyz.shi.utils.MybatisUtils;
import java.util.List;

public class PersonDaoImpl implements PersonDao {
@Override
public List<Person> findAll() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 命名空间+id,这就是命名空间的作用:便于区分
List<Person> personList = sqlSession.selectList("personMapper.findAll");
sqlSession.close();
return personList;
}

@Override
public Person queryOne(int id) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
Person person = sqlSession.selectOne("personMapper.queryOne", id);
sqlSession.close();
return person;

}

@Override
public int insert(Person person) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.insert("personMapper.insertPerson", person);
sqlSession.commit();
sqlSession.close();
return num;
}

@Override
public int modify(Person person) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.update("personMapper.modifyPerson", person);
sqlSession.commit();
sqlSession.close();
return num;
}

@Override
public int delete(int id) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.delete("personMapper.deletePerson", id);
sqlSession.commit();
sqlSession.close();
return num;
}

}

  • sqlsession代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package xyz.shi.utils;

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 java.io.IOException;
import java.io.InputStream;

public class MybatisUtils {

//sqlSession工厂
private static SqlSessionFactory sqlSessionFactory;

//静态代码块,直接项目跑起来直接装载
static {
//设置要读取的资源路径
String resource = "mybatis.config.xml";
//声明一个输入流,方便后面读取
InputStream inputStream = null;

try {
//通过ibatis包下的资源读取的方法,通过提前设定好的路径将mybatis的核心配置文件读取进来,用来建造工厂
inputStream = Resources.getResourceAsStream(resource);
//new一个建造者,通过建造者创建一个带核心配置文件的工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}

//通过工厂打开一个对数据库的会话
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}

  • 测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.junit.Test;
import xyz.shi.dao.PersonDao;
import xyz.shi.dao.impl.PersonDaoImpl;
import xyz.shi.domain.IdCard;
import xyz.shi.domain.Person;

import java.util.Arrays;
import java.util.List;

public class PersonDaoTest {
private PersonDao personDao = new PersonDaoImpl();
@Test
public void TestFindAll() {
//在查询之前,设置分页条件 显示第一页,展示3条数据
Page<Object> page = PageHelper.startPage(1, 3);

List<Person> personList = personDao.findAll();

PageInfo<Person> pageInfo = new PageInfo<>(personList, 5);

for (Person person:personList) {
System.out.println("------每个用户的信息-------");
System.out.println(person.getName());
System.out.println(person.getIdCard().getCardNo());
}
System.out.println();
///xxx
System.out.println("---------全面配置信息:--------");
System.out.println("总数据量 :"+pageInfo.getTotal());
System.out.println("每页的数量:"+pageInfo.getPageSize());
System.out.println("当前页码:"+pageInfo.getPageNum());
System.out.println("是否有上一页:"+pageInfo.isHasPreviousPage());
System.out.println("上一页是:"+pageInfo.getPrePage());
System.out.println("是否有下一页:"+pageInfo.isHasNextPage());
System.out.println("下一页是:"+pageInfo.getNextPage());
System.out.println("是否是第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否是最后一页:"+pageInfo.isIsLastPage());
System.out.println("导航页的第一个页码是:"+pageInfo.getNavigateFirstPage());
System.out.println("导航页的最后一个页码是:"+pageInfo.getNavigateLastPage());
System.out.println("每页显示的页码个数:"+pageInfo.getNavigatePages());
System.out.println("页码数:"+ Arrays.toString(pageInfo.getNavigatepageNums()));
}
@Test
public void TestQueryOne() {
Person person = personDao.queryOne(16);
System.out.println(person.getName());
System.out.println(person.getIdCard().getCardNo());
}
@Test
public void TestAddPerson() {
Person person = new Person();
person.setName("山大王");

IdCard idCard = new IdCard();
idCard.setCardNo("222");
idCard.setId(14);

person.setIdCard(idCard);

personDao.insert(person);
}

@Test
public void TestModifyPerson() {
Person person = new Person();
person.setName("山大王234");
person.setId(29);

IdCard idCard = new IdCard();
idCard.setId(17);

person.setIdCard(idCard);
personDao.modify(person);
}

@Test
public void TestDelete() {
personDao.delete(24);
}
}

一对多

  • 这篇文章 介绍了对Hibernate的关系映射

  • 直接用表student(多对一)、grade(一对多,一个年级下有多个学生)

  • 直接用Student、Grade实体类

  • src-main-resources-gradeMapper.xml 新建如下grade表的增删改查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?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="gradeMapper">
<!-- 定义封装resultMap
property 实体中对应的属性
column 数据库对应的列(select查询返回的列表)
-->
<resultMap id="gradeStudentMap" type="xyz.shi.domain.Grade">
<id property="id" column="gid"/>
<result property="name" column="gname"/>
<!--一对多关系的时候,一方使用collection标签映射多方 -->
<collection property="students" ofType="xyz.shi.domain.Student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>

</collection>
</resultMap>
<!--配置查询所有,重复的列需要重命名-->
<select id="findAll" resultMap="gradeStudentMap">
select g.id as gid, g.name as gname, s.id as sid, s.name as sname from grade g left join student s on g.id = s.gid
</select>
<!-- 通过id(唯一)获取用户-->
<select id="queryOne" parameterType="int" resultMap="gradeStudentMap">
select s.name as sname,g.name as gname, g.id as gid, s.id as sid from grade g, student s where g.id = s.gid and g.id=#{id}
</select>
<!-- 插入 userGeneratedKeys和keyProperty属性可以让插入后对象获得本身自己的id
-->
<insert id="insertGrade" parameterType="Grade"
useGeneratedKeys="true" keyProperty="id">
insert into grade (name) values(#{name})
</insert>
<insert id="insertStudent" parameterType="xyz.shi.domain.Student">
INSERT INTO student (name, gid) VALUES (#{name}, #{grade.id})
</insert>
<!-- 批量新增的时候,注意接收的对象是一个列表,需要在动态拼接sql的时候遍历参数集合对象 -->
<insert id="insertBatchStudent" parameterType="java.util.List">
Insert into student (name,gid) values
<foreach collection="list" item="item" separator=",">
(#{item.name},#{item.grade.id})
</foreach>
</insert>
<update id="updateBatchStudent" parameterType="java.util.List">
<foreach collection="list" item="item" separator=";">
update student set name = #{item.name},gid = #{item.grade.id} where id = #{item.id}
</foreach>
</update>
<delete id="deleteBatchStudent" parameterType="java.util.List">
delete from student where id in
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
</mapper>

collection 维护一对多

注意foreach的用法

  • src-main-resources-studentMapper.xml 新建如下student表的查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?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="studentMapper">
<!-- 定义封装resultMap
property 实体中对应的属性
column 数据库对应的列(select查询返回的列表)
-->
<resultMap type="xyz.shi.domain.Student" id="StudentGradeResult">
<id column="sid" jdbcType="BIGINT" property="id" />
<result column="sname" jdbcType="VARCHAR" property="name" />
<!-- 多对一关系的时候,多方使用association标签映射一方-->
<!-- <association property="grade" resultMap="StudentResult"></association>-->
<association property="grade" javaType="xyz.shi.domain.Grade">
<id column="gid" property="id" />
<result column="gname" property="name" />
</association>

</resultMap>
<select id="queryOne" parameterType="int" resultMap="StudentGradeResult">
select s.name as sname,g.name as gname, g.id as gid, s.id as sid from student s,grade g where g.id = s.gid and s.id=#{id}
</select>
</mapper>

association 维护多对一

  • 编写班级grade的接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package xyz.shi.dao;

import xyz.shi.domain.Grade;
import xyz.shi.domain.Student;

import java.util.List;

public interface GradeDao {
List<Grade> findAll();
Grade queryOne(int id);
int insert(Grade grade);
// 批量插入学生
int insertBatchStudent(List<Student> students);
int updateBatchStudent(List<Student> students);
int deleteBatchStudent(List<Integer> ids);
}
  • 实现grade接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package xyz.shi.dao.impl;

import org.apache.ibatis.session.SqlSession;
import xyz.shi.dao.GradeDao;
import xyz.shi.domain.Grade;
import xyz.shi.domain.Student;
import xyz.shi.utils.MybatisUtils;

import java.util.List;

public class GradeDaoImpl implements GradeDao {
@Override
public List<Grade> findAll() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 命名空间+id,这就是命名空间的作用:便于区分
List<Grade> gradesList = sqlSession.selectList("gradeMapper.findAll");
sqlSession.commit();
sqlSession.close();
return gradesList;
}

@Override
public Grade queryOne(int id) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
Grade grade = sqlSession.selectOne("gradeMapper.queryOne", id);
sqlSession.close();
return grade;
}

@Override
public int insert(Grade grade) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.insert("gradeMapper.insertGrade", grade);
sqlSession.commit();
sqlSession.close();
return num;
}

@Override
public int insertBatchStudent(List<Student> students) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.insert("gradeMapper.insertBatchStudent",students);
sqlSession.commit();
sqlSession.close();
return num;
}

@Override
public int updateBatchStudent(List<Student> students) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.update("gradeMapper.updateBatchStudent",students);
sqlSession.commit();
sqlSession.close();
return num;
}

@Override
public int deleteBatchStudent(List<Integer> ids) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.delete("gradeMapper.deleteBatchStudent",ids);
sqlSession.commit();
sqlSession.close();
return num;
}
}

  • 执行测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.junit.Test;
import xyz.shi.dao.GradeDao;
import xyz.shi.dao.PersonDao;
import xyz.shi.dao.StudentDao;
import xyz.shi.dao.impl.GradeDaoImpl;
import xyz.shi.dao.impl.PersonDaoImpl;
import xyz.shi.dao.impl.StudentDaoImpl;
import xyz.shi.domain.Grade;
import xyz.shi.domain.Person;
import xyz.shi.domain.Student;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

public class GradeDaoTest {
private GradeDao gradeDao = new GradeDaoImpl();
@Test
public void findAll() {
//在查询之前,设置分页条件 显示第一页,展示10条数据
Page<Object> page = PageHelper.startPage(1, 10);

List<Grade> gradeList = gradeDao.findAll();

PageInfo<Grade> pageInfo = new PageInfo<>(gradeList, 5);

for (Grade grade:gradeList) {
System.out.println("------每个用户的信息-------");
System.out.println(grade.getName());
System.out.println(grade.getStudents());
List<Student> students = grade.getStudents();
for(Student student: students) {
System.out.println(student.getName());

}

}
System.out.println();
///xxx
System.out.println("---------全面配置信息:--------");
System.out.println("总数据量 :"+pageInfo.getTotal());
System.out.println("每页的数量:"+pageInfo.getPageSize());
System.out.println("当前页码:"+pageInfo.getPageNum());
System.out.println("是否有上一页:"+pageInfo.isHasPreviousPage());
System.out.println("上一页是:"+pageInfo.getPrePage());
System.out.println("是否有下一页:"+pageInfo.isHasNextPage());
System.out.println("下一页是:"+pageInfo.getNextPage());
System.out.println("是否是第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否是最后一页:"+pageInfo.isIsLastPage());
System.out.println("导航页的第一个页码是:"+pageInfo.getNavigateFirstPage());
System.out.println("导航页的最后一个页码是:"+pageInfo.getNavigateLastPage());
System.out.println("每页显示的页码个数:"+pageInfo.getNavigatePages());
System.out.println("页码数:"+ Arrays.toString(pageInfo.getNavigatepageNums()));
}
@Test
public void queryOne() {
Grade grade = gradeDao.queryOne(2);
System.out.println(grade.getName());
List<Student> students = grade.getStudents();
for(Student student: students) {
System.out.println(student.getName());
}
}
@Test
public void queryOneStudent(){
StudentDao studentDao = new StudentDaoImpl();
Student student = studentDao.queryOne(3);
System.out.println(student);
}
@Test
public void insertGrade() {
Grade grade = new Grade();
grade.setName("初中");
gradeDao.insert(grade);
}
@Test
public void insertBatchStudent() {
Grade grade = new Grade();
grade.setName("初二");
gradeDao.insert(grade);

List<Student> students = new ArrayList<>();

Student student1 = new Student();
student1.setName("s1");
student1.setGrade(grade);
students.add(student1);

Student student2 = new Student();
student2.setName("s2");
student2.setGrade(grade);
students.add(student2);

gradeDao.insertBatchStudent(students);
}
@Test
public void updateBatchStudent() {
Grade grade = new Grade();
grade.setId(25);

List<Student> students = new ArrayList<>();
students.add(new Student(41, "新姓名1", grade));
students.add(new Student(42, "新姓名2", grade));
students.add(new Student(43, "新姓名3", grade));

gradeDao.updateBatchStudent(students);
}

@Test
public void deleteBatchStudent() {
List<Integer> ids = new ArrayList<>();
ids.add(3);
ids.add(4);
ids.add(50);
gradeDao.deleteBatchStudent(ids);
// 如果想删除班级和学生呢,可以先删除学生然后再次删除年纪,就是写两个delete语句
//delete from student where gid = #{gid}
//delete from grade where id = #{gid}
}

}

多对多

  • 直接用表student、course(课程表)

  • 直接用Student、course实体类

  • src-main-resources-studentMapper.xml 新建如下student表的增删改查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<?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="studentMapper">
<!-- 定义封装resultMap
property 实体中对应的属性
column 数据库对应的列(select查询返回的列表)
-->
<resultMap type="xyz.shi.domain.Student" id="StudentGradeResult">
<id column="sid" jdbcType="BIGINT" property="id" />
<result column="sname" jdbcType="VARCHAR" property="name" />
<!-- 多对一关系的时候,多方使用association标签映射一方-->
<!-- <association property="grade" resultMap="StudentResult"></association>-->
<association property="grade" javaType="xyz.shi.domain.Grade">
<id column="gid" property="id" />
<result column="gname" property="name" />
</association>
</resultMap>

<resultMap type="xyz.shi.domain.Student" id="StudentCourseResult">
<id column="sid" jdbcType="BIGINT" property="id" />
<result column="sname" jdbcType="VARCHAR" property="name" />
<!-- 一对多 -->
<collection property="courses" ofType="xyz.shi.domain.Course">
<id property="id" column="cid"/>
<result property="name" column="cname"/>

</collection>
</resultMap>
<select id="queryOne" parameterType="int" resultMap="StudentCourseResult">
select s.name as sname,g.name as gname, g.id as gid, s.id as sid from student s,grade g where g.id = s.gid and s.id=#{id}
</select>
<select id="findAllStuCourse" resultMap="StudentCourseResult">
SELECT c.name as cname, c.id as cid, s.id as sid, s.name as sname
FROM student s
INNER JOIN student_course sc ON s.id = sc.student_id
INNER JOIN course c ON sc.course_id = c.id
</select>

<insert id="insertStudent" parameterType="xyz.shi.domain.Student"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO student (name, gid) VALUES (#{name}, #{grade.id})
</insert>
<!---学生关联多个课程 -->
<insert id="batchInsertStudentCourse">
INSERT INTO student_course (student_id, course_id)
VALUES
<foreach collection="courseIds" item="courseId" separator=",">
(#{studentId}, #{courseId})
</foreach>
</insert>
<update id="updateStudent" parameterType="Student">
UPDATE student
SET name = #{name}
WHERE id = #{id}
</update>
<update id="updateStudentCourse" parameterType="java.util.Map">
UPDATE student SET name = #{student.name} WHERE id = #{student.id};
<!-- 先清空关联关系,然后重写插入 -->
DELETE FROM student_course WHERE student_id = #{student.id};
<foreach collection="courseIds" item="courseId" separator=";">
INSERT INTO student_course (student_id, course_id) VALUES (#{student.id}, #{courseId})
</foreach>
</update>
<delete id="deleteStudentAndRelations" parameterType="int">
DELETE FROM student WHERE id = #{id};
DELETE FROM student_course WHERE student_id = #{id};
</delete>
</mapper>
  • studentDao接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package xyz.shi.dao;

import xyz.shi.domain.Course;
import xyz.shi.domain.Grade;
import xyz.shi.domain.Student;

import java.util.List;
import java.util.Map;

public interface StudentDao {
Student queryOne(int id);
List<Student> findAll();
int insert(Student student);
int batchInsertStudentCourse(Map<String, Object> parameterMap);
int updateStudent(Student student);
int updateStudentCourse(Map<String, Object> parameterMap);
int deleteStudentAndRelations(Integer id);
}
  • 实现studentDao接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package xyz.shi.dao.impl;

import org.apache.ibatis.session.SqlSession;
import xyz.shi.dao.StudentDao;
import xyz.shi.domain.Student;
import xyz.shi.utils.MybatisUtils;

import java.util.List;
import java.util.Map;

public class StudentDaoImpl implements StudentDao {

@Override
public Student queryOne(int id) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
Student student = sqlSession.selectOne("studentMapper.queryOne", id);
sqlSession.close();
return student;
}

@Override
public List<Student> findAll() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
List<Student> students = sqlSession.selectList("studentMapper.findAllStuCourse");
sqlSession.commit();
sqlSession.close();
return students;

}

@Override
public int insert(Student student) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.insert("studentMapper.insertStudent", student);
sqlSession.commit();
sqlSession.close();
return num;
}

@Override
public int batchInsertStudentCourse(Map<String, Object> parameterMap) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.insert("studentMapper.batchInsertStudentCourse", parameterMap);
sqlSession.commit();
sqlSession.close();
return num;
}

@Override
public int updateStudent(Student student) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.update("studentMapper.updateStudent", student);
sqlSession.commit();
sqlSession.close();
return num;
}

@Override
public int updateStudentCourse(Map<String, Object> parameterMap) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.update("studentMapper.updateStudentCourse", parameterMap);
sqlSession.commit();
sqlSession.close();
return num;
}

@Override
public int deleteStudentAndRelations(Integer id) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int num = sqlSession.update("studentMapper.deleteStudentAndRelations", id);
sqlSession.commit();
sqlSession.close();
return num;
}
}

  • 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.junit.Test;
import xyz.shi.dao.GradeDao;
import xyz.shi.dao.PersonDao;
import xyz.shi.dao.StudentDao;
import xyz.shi.dao.impl.StudentDaoImpl;
import xyz.shi.domain.Course;
import xyz.shi.domain.Grade;
import xyz.shi.domain.Person;
import xyz.shi.domain.Student;

import java.util.*;

public class StudentDaoTest {
private StudentDao studentDao = new StudentDaoImpl();

@Test
public void findAllStuCourse() {
//在查询之前,设置分页条件 显示第一页,展示10条数据
Page<Object> page = PageHelper.startPage(1, 3);

List<Student> students = studentDao.findAll();

PageInfo<Student> pageInfo = new PageInfo<>(students, 5);

for (Student student:students) {
System.out.println("------每个用户的信息-------");
System.out.println(student);
System.out.println(student.getCourses());
List<Course> courses = student.getCourses();
for(Course course: courses) {
System.out.println(course.getName());
System.out.println(course.getId());
}
}
System.out.println();
///xxx
System.out.println("---------全面配置信息:--------");
System.out.println("总数据量 :"+pageInfo.getTotal());
System.out.println("每页的数量:"+pageInfo.getPageSize());
System.out.println("当前页码:"+pageInfo.getPageNum());
System.out.println("是否有上一页:"+pageInfo.isHasPreviousPage());
System.out.println("上一页是:"+pageInfo.getPrePage());
System.out.println("是否有下一页:"+pageInfo.isHasNextPage());
System.out.println("下一页是:"+pageInfo.getNextPage());
System.out.println("是否是第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否是最后一页:"+pageInfo.isIsLastPage());
System.out.println("导航页的第一个页码是:"+pageInfo.getNavigateFirstPage());
System.out.println("导航页的最后一个页码是:"+pageInfo.getNavigateLastPage());
System.out.println("每页显示的页码个数:"+pageInfo.getNavigatePages());
System.out.println("页码数:"+ Arrays.toString(pageInfo.getNavigatepageNums()));
}

@Test
public void insertBatchStudent() {
// 设置年纪
Grade grade = new Grade();
grade.setId(2);

Student student1 = new Student();
student1.setName("刘小龙1");
// 关联当前学生的年级
student1.setGrade(grade);
studentDao.insert(student1);

Map<String, Object> parameterMap = new HashMap<>();
parameterMap.put("studentId", student1.getId());
// 手动设置多个科目信息,也可以做批量新增科目
List<Integer> courseIds = Arrays.asList(17, 18);
parameterMap.put("courseIds", courseIds);

studentDao.batchInsertStudentCourse(parameterMap);
}
@Test
public void updateStudentCourse() {
// 要更新的学生信息
Student student = new Student();
student.setId(41);
// 学生新的名字
student.setName("张三");

Map<String, Object> parameterMap = new HashMap<>();
parameterMap.put("student", student);
// 手动设置多个科目信息,也可以做批量新增科目
List<Integer> courseIds = Arrays.asList(29, 30);
parameterMap.put("courseIds", courseIds);
// 更新学生的关联的课程
studentDao.updateStudentCourse(parameterMap);
}
@Test
public void deleteStudentAndRelations() {
studentDao.deleteStudentAndRelations(44);
}
}

总结

  • mapper中resultMap 下用collection为一对多的关联,用association为一对一的关联

  • 一对多或者多对多,更新关系时,先批量删除,然后再批量插入

  • 批量修改数据,需要在db字符串中加上&allowMultiQueries=true

  • 缓存,本次不做演练看目标博客即可

  • 代码在这里