在确保可运行项目能够正确无误地运行之后,再严格照着教程的步骤,对代码模仿一遍。模仿过程难免代码有出入,导致无法得到期望的运行结果,此时此刻通过比较正确答案 ( 可运行项目 ) 和自己的代码,来定位问题所在。采用这种方式,学习有效果,排错有效率,可以较为明显地提升学习速度,跨过学习路上的各个槛。
基于框架的程序要成功运行,对于JAR包的版本,配置文件的正确性有着苛刻的要求,任何一个地方出错了,都会导致框架程序运行失败。 请务必严格按照教程的指导,完全模仿操作,直到成功看到运行效果。 第一次成功之后,信心,思路都会有较好的铺垫,然后再根据自己的疑惑,在“成功”的代码上做原本想做的改动和调整,这样可以大大节约学习的时间,提高效率,切勿一来就擅自改动,给自己的学习制造障碍!!!
源码:
链接:https://pan.baidu.com/s/1kJCSSK_nTvwvct-SeMGFvw?pwd=j1v8
提取码:j1v8
在实际应用中,对数据库的操作会涉及多张表,这在面向对象中就涉及对象与对象之间的关联关系。针对多表之间的操作,MyBatis提供了关联映射,通过关联映射来处理与对象之间的关联联系。
在关系型数据库中,多表之间存在着三种关联关系,分别为一对一、一对多和多对多。
- 一对一:在任意一方引入对方主键作为外键。
- 一对多:在“多”的一方,,添加“一”的一方的主键作为外键。
- 多对多:产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键或使用新的字段作为主键。
目录
前提:创建一个java项目,并导入相应的jar包。
一对一:
通过学生与学生证之间的一对一关联关系为例。查询学生及其关联的学生证信息是先通过查询学生表中的主键来获取学生信息,然后通过表中的外键来获取学生证表中的学生证号信息。
1.创建数据库和表并插入一些数据。
create database db_mybatis ;
use db_mybatis;
create table tb_studentidcard(
id int primary key auto_increment ,
CODE varchar(8)
);
insert into tb_studentidcard values(null,'12345678');
insert into tb_studentidcard values(null,'87654321');
create table tb_student(
id int primary key auto_increment ,
name varchar(32) ,
sex char(1) ,
card_id int unique ,
foreign key (card_id) references tb_studentidcard(id)
);
insert into tb_student values(null,'zyy', 'f','1');
insert into tb_student values(null,'wrr' ,'m','2');
2.创建一个包命名为po,在该包内创建两个实体类StudentIdCard和Student。
StudentIdCard.java
package po;
public class StudentIdCard {
private Integer id;
private String code;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id=id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code=code;
}
public String toString() {
return "StudentIdCard [id="+id+",code="+code+"]";
}
}
Student.java
package po;
public class Student {
private Integer id;
private String name;
private String sex;
private StudentIdCard studentIdCard;
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 StudentIdCard getStudentIdCard() {
return studentIdCard;
}
public void setStudentIdCard(StudentIdCard studentIdCard) {
this.studentIdCard=studentIdCard;
}
public String toString() {
return "Student[id="+id+",name="+name+",sex="+sex+",studentidcard="+studentIdCard+",]";
}
}
3.创建一个包命名为mapper,创建StudentIdCardMapper.xml和StudentMapper.xml并在两个映射文件中编写一对一关联映射查询的配置信息。
StudentIdCardMapper.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="mapper.StudentIdCardMapper">
<select id="findStudentIdCardById" parameterType="Integer" resultType="po.StudentIdCard">
select * from tb_studentidcard where id=#{id}
</select>
</mapper>
StudentMapper.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="mapper.StudentMapper">
<select id="findStudentById" parameterType="Integer" resultMap="StudentIdCardWithStudentResult">
select * from tb_student where id=#{id}
</select>
<resultMap type="po.Student" id="StudentIdCardWithStudentResult">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<association property="studentIdCard" column="card_id" javaType="po.StudentIdCard" select="mapper.StudentIdCardMapper.findStudentIdCardById" />
</resultMap>
</mapper>
4.在src目录下创建核心配置文件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>
<typeAliases>
<package name="mybatis"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db_mybatis?characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/StudentIdCardMapper.xml" />
<mapper resource="mapper/StudentMapper.xml" />
</mappers>
</configuration>
5.创建一个包命名为test,在包内编写测试程序test01
package test;
import java.io.InputStream;
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 po.Student;
public class test01 {
public static void main(String[] args) throws Exception{
String resourse="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resourse);
SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession=sessionFactory.openSession();
Student student=sqlSession.selectOne("mapper.StudentMapper.findStudentById",1);
System.out.println(student);
sqlSession.commit();
sqlSession.close();
}
}
使用MyBatis嵌套查询的方式查询出了学生及其关联的学生证信息,这就是MyBatis的一对一关联查询。
改进:
虽然使用嵌套查询的方式比较简单,但是嵌套查询的方式要执行多条SQL语句,这对于大型数据集合和列表展示不是很好,因为这样可能会导致成百上千条关联的SQL语句被执行,从而极大地消耗数据库性能,并且会降低查询效率。为此,MyBatis提供了嵌套结果的方式进行关联查询。
对StudentMapper.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="mapper.StudentMapper">
<select id="findStudentById" parameterType="Integer" resultMap="StudentIdCardWithStudentResult">
select s.* ,sidcard.code
from tb_student s, tb_studentidcard sidcard
where s.card_id =sidcard.id and s.id =#{id}
</select>
<resultMap type="po.Student" id="StudentIdCardWithStudentResult">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<association property="studentIdCard" javaType="po.StudentIdCard" >
<id property="id" column="card_id"/>
<result property="code" column="code"/>
</association>
</resultMap>
</mapper>
运行test01.java结果与上面相同。但是MyBatis嵌套结果的方式只执行了一条SQL语句。
在使用MyBatis嵌套查询方式进行关联查询映射时,使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。MyBatis默认没有开启延迟加载,需要在核心配置文件mybatis-config.xml中使用<setting>元素进行配置。
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
在映射文件中,MyBatis关联映射的<association>元素和<collection>元素中都已经默认配置了延迟加载属性,即默认属性 fetchType="lazy" ,所以在配置文件中开启延迟加载后,无须在映射文件中再做配置。
一对多:
在实际应用中,应用更多的关联关系是一对多(或多对一)。例如一个系有多个老师,也即多个老师属于一个系。
<resultMap>元素中,包含了一个<collection>子元素,MyBatis就是通过该元素来处理一对多关联关系的。
1.我们在db_mybatis数据库中创建tb_banji表和tb_teacher表并插入几条数据
create table tb_xi(
id int primary key auto_increment ,
name varchar(32)
);
insert into tb_banji values(null,'xi01');
insert into tb_banji values(null,'xi02');
create table tb_teacher(
id int primary key auto_increment ,
name varchar(32) ,
sex char(1) ,
xi_id int ,
foreign key (xi_id) references tb_banji(id)
);
insert into tb_teacher values(null,'qdw', 'f',1);
insert into tb_teacher values(null,'hxy' ,'m',2);
2.在po包中创建实体类Xi和Teacher
Teacher.java
package po;
public class Teacher {
private Integer id;
private String name;
private String sex;
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 String toString() {
return "Student[id="+id+",name="+name+",sex="+sex+"]";
}
}
Xi.java
package po;
import java.util.List;
public class Xi {
private Integer id;
private String name;
private List<Teacher> TeacherList;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id=id;
}
public String getCode() {
return name;
}
public void setName(String name) {
this.name=name;
}
public List<Teacher> getTeacherList() {
return TeacherList;
}
public void setTeacherList(List<Teacher> teacherList) {
this.TeacherList=teacherList;
}
public String toString() {
return "StudentIdCard [id="+id+",name="+name+",teacherList="+TeacherList+"]";
}
}
3.在mapper包下创建系映射文件XiMapper.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="mapper.XiMapper">
<select id="findXiWithTeacher" parameterType="Integer" resultMap="XiWithTeacherResult">
select x.* ,t.id as teacher_id ,t.name as tname ,t.sex
from tb_xi x, tb_teacher t
where x.id =t.xi_id and x.id =#{id}
</select>
<resultMap type="po.Xi" id="XiWithTeacherResult">
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="teacherList" ofType="po.Teacher">
<id property="id" column="teacher_id"/>
<result property="name" column="tname"/>
<result property="sex" column="sex"/>
</collection>
</resultMap>
</mapper>
4.在mybatis-config.xml核心配置文件中添加<mapper>路径配置。
<mapper resource="mapper/XiMapper.xml" />
5.在test包创建test02类,进行测试。
package test;
import java.io.InputStream;
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 po.Xi;
public class test02 {
public static void main(String[] args) throws Exception{
String resourse="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resourse);
SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession=sessionFactory.openSession();
Xi xi=sqlSession.selectOne("mapper.XiMapper.findXiWithTeacher",1);
System.out.println(xi);
sqlSession.commit();
sqlSession.close();
}
}
运行结果:
班级与学生之间是一对多的关联关系,但如果从单个学生的角度出发,一个学生只能属于一个班级,即一对一的关联关系。
多对多:
在实际项目开发中,多对多的关联关系也是非常常见的。以学生和课程为例,一个学生可以选修多门课程,而一门课程又可以被多个学生选修,学生和课程就属于多对多的关联关系。
1.db_mybatis数据库中创建tb_couse表和tb_electivecourse表和tb_student表(一对一创建)
create table tb_course(
id int primary key auto_increment ,
name varchar(32) ,
code vaRchar(32)
)
insert into tb_course values(null,'java' ,'001');
insert into tb_course values(null,'javaweb' ,'101');
create table tb_electivecourse(
id int primary key auto_increment ,
student_id int ,
course_id int ,
foreign key (student_id) references tb_student(id) ,
foreign key (course_id) references tb_course(id)
)
insert into tb_electivecourse values(null,1,1);
insert into tb_electivecourse values(null,1,2);
insert into tb_electivecourse values(null,2,2);
2.在po包下创建Course类并修改Student类
Course.java
package po;
import java.util.List;
public class Course {
private Integer id;
private String name;
private String code;
private List<Student> studentList;
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 getCode() {
return code;
}
public void setCode(String code) {
this.code=code;
}
public List<Student> getStudentlist() {
return studentList;
}
public void setStudentlist(List<Student> studentList) {
this.studentList=studentList;
}
public String toString() {
return "Course [id="+id+",name="+name+",code="+code+",studentlist="+studentList+"]";
}
}
Student.java
package po;
import java.util.List;
public class Student {
private Integer id;
private String name;
private String sex;
private StudentIdCard studentIdCard;
private List<Course> courseList;
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 StudentIdCard getStudentIdCard() {
return studentIdCard;
}
public void setStudentIdCard(StudentIdCard studentIdCard) {
this.studentIdCard=studentIdCard;
}
public List<Course> getCourselist() {
return courseList;
}
public void setCourselist(List<Course> courselist) {
this.courseList=courselist;
}
public String toString() {
return "Student[id="+id+",name="+name+",sex="+sex+"]";
}
}
3.在mapper包下创建CourseMapper.xml映射文件和StudentMapper.xml
CourseMapper.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="mapper.CourseMapper">
<select id="findCourseWithStudent" parameterType="Integer" resultMap="CourseWithStudentResult">
select * from tb_course where id=#{id}
</select>
<resultMap type="po.Course" id="CourseWithStudentResult">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="code" column="code"/>
<collection property="studentList" ofType="po.Student" column="id" select="mapper.StudentMapper.findStudentById">
</collection>
</resultMap>
</mapper>
修改StudentMapper.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="mapper.StudentMapper">
<select id="findStudentById" parameterType="Integer" resultType="po.Student">
select * from tb_student where id in (
select student_id from tb_electivecourse where course_id=#{id}
)
</select>
</mapper>
4.修改mybatis-config.xml,添加映射文件路径
<mapper resource="mapper/CourseMapper.xml"/>
5.在test包下创建test03类进行测试。
package test;
import java.io.InputStream;
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 po.Course;
public class test03 {
public static void main(String[] args) throws Exception{
String resourse="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resourse);
SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession=sessionFactory.openSession();
Course course=sqlSession.selectOne("mapper.CourseMapper.findCourseWithStudent",1);
System.out.println(course);
sqlSession.commit();
sqlSession.close();
}
}
运行结果
如果喜欢用多表关联查询的SQL语句,可以对CourseMapper.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="mapper.CourseMapper">
<select id="findCourseWithStudent" parameterType="Integer" resultMap="CourseWithStudentResult">
select c.* ,s.id as sid ,s.name as sname ,s.sex as ssex
from tb_course c ,tb_student s,tb_electivecourse ec
where ec.course_id=c.id
and ec.student_id =s.id and c.id=#{id}
</select>
<resultMap type="po.Course" id="CourseWithStudentResult">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="code" column="code"/>
<collection property="studentList" ofType="po.Student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="sex" column="ssex"/>
</collection>
</resultMap>
</mapper>
运行结果与上面相同。