本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Mybatis处理数据库中关联关系
数据库关联关系
# 数据库关联关系
- 一对一关联关系、一对多关联关系、多对多关联关系
- 一对一:用户信息 --> 唯一的身份信息
- 一对多:部门信息 --> 员工信息
- 多对多:老师信息 --> 学生信息 还有 学生信息 --> 课程信息
1. 一对一关联关系处理
mybatis处理一对一关联关系中保存(插入操作)
-
数据库中有如下两张表:
-- 一对一关联关系 -- 用户信息表 create table t_person( id int(6) PRIMARY KEY auto_increment, name varchar(40), age int(3), cardno varchar(18) REFERENCES t_info(cardno) ); -- 身份信息表 create table t_info( id int(6) PRIMARY KEY auto_increment, cardno varchar(18), address varchar(100) );
-
mybatis中保存身份信息
java中身份对象:
public class Info { private Integer id; private String cardno; // 身份证号 private String address; // 地址 // 为了不占用太大的篇幅,get、set、toString方法就不复制了,但是这些方法是有的 get,set,toString... }
身份信息接口InfoDAO:
public interface InfoDAO { // 保存身份信息的方法 int save(Info info); }
创建mapper配置文件,并在文件里面添加save对应的实现:
<mapper namespace="com.baizhi.dao.InfoDAO"> <!--save--> <insert id="save" parameterType="com.baizhi.eneity.Info" keyProperty="id" useGeneratedKeys="true"> insert into t_info values (#{id}, #{cardno}, #{address}) </insert> </mapper>
另外还要在mybatis-config.xml文件中注册mapper配置文件:
<!--注册项目中mapper.xml配置文件--> <mappers> <!--身份信息--> <mapper resource="com/baizhi/mapper/InfoDAO.xml"/> </mappers>
保存身份信息的java代码:
// 保存信息 @Test public void testSaveInfo() throws IOException { SqlSession sqlSession = MybatisUtil.getSqlSession(); InfoDAO infoDAO = sqlSession.getMapper(InfoDAO.class); try { Info info = new Info(); info.setCardno("165342789384233455"); info.setAddress("北京市朝阳区"); infoDAO.save(info); sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); sqlSession.rollback(); } finally { MybatisUtil.close(sqlSession); } }
结果:
-
mybatis中保存用户信息
java中用户对象:
// 用户信息 public class Person { private Integer id; private String name; private Integer age; private String cardno; // 外键 // 为了不占用太大的篇幅,get、set、toString方法就不复制了,但是这些方法是有的 get,set,toString... }
用户信息接口PersonDAO:
public interface PersonDAO { // 保存用户信息方法 public void save(Person person); }
创建mapper配置文件,并在文件里面添加save对应的实现:
<mapper namespace="com.baizhi.dao.PersonDAO"> <!--保存用户信息的方法--> <insert id="save" parameterType="com.baizhi.eneity.Person" keyProperty="id" useGeneratedKeys="true"> insert into t_Person values (#{id}, #{name}, #{age}, #{cardno}) </insert> </mapper>
另外还要在mybatis-config.xml文件中注册mapper配置文件:
<!--注册项目中mapper.xml配置文件--> <mappers> <!--用户信息--> <mapper resource="com/baizhi/mapper/PersonDAO.xml"/> </mappers>
保存用户信息的java代码:
// 保存用户信息 @Test public void testSavePerson() throws IOException { SqlSession sqlSession = MybatisUtil.getSqlSession(); PersonDAO personDAO = sqlSession.getMapper(PersonDAO.class); try { Person person = new Person(); person.setName("小陈"); person.setAge(23); // 外键信息 person.setCardno("165342789384233455"); personDAO.save(person); sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); sqlSession.rollback(); } finally { MybatisUtil.close(sqlSession); } }
结果:
mybatis处理一对一关联关系中查询(查询操作)
-
根据用户信息并将他(她)的身份信息一并查询
在java中用对象表示关系,我们可以在用户类里面定义一个身份信息对象,表示关系。
在PersonDAO接口中定义查询方法:
// 查询所有用户信息(查询用户信息的同时把身份信息也查询出来) List<Person> queryAll();
在对应的mapper配置文件中需要添加的内容:
<resultMap id="personMap" type="com.baizhi.eneity.Person"> <id column="id" property="id"/> <result column="name" property="name"/> <result column="age" property="age"/> <result column="cardno" property="cardno"/> <!--处理一对一 association: 用来处理一对一关联关系的标签 property: 用来书写封装的关系属性名--> <!--javaType: 关系属性的java类型--> <association property="info" javaType="com.baizhi.eneity.Info"> <id column="iid" property="id"/> <result column="icardno" property="cardno"/> <result column="address" property="address"/> </association> </resultMap> <!--查询所有(查询用户信息的同时也把身份信息查出来)--> <select id="queryAll" resultMap="personMap"> select p.id, p.name, p.age, p.cardno, i.id iid, i.cardno icardno, i.address from t_person p left join t_info i on p.cardno = i.cardno </select>
查询的java代码:
// 查询所有用户信息(查询用户信息的同时也把身份信息查询出来) // 查询不需要控制事务,所以查询完后直接关闭,不用try/catch/finally @Test public void testQueryAll() throws IOException { SqlSession sqlSession = MybatisUtil.getSqlSession(); PersonDAO personDAO = sqlSession.getMapper(PersonDAO.class); // maven默认jdk1.7,lambda表达式是在1.8添加的,这里 Alt + 回车 personDAO.queryAll().forEach(person -> { System.out.println("当前用户信息:" + person + "身份信息:" + person.getInfo()); }); MybatisUtil.close(sqlSession); }
结果:
2. 一对多关联关系处理
数据库表:
-- 部门表
create table t_dept(
id int(6) primary key auto_increment,
name varchar(40)
);
-- 员工表
create table t_emp(
id int(6) primary key auto_increment,
name varchar(40),
age int(3),
bir timestamp,
deptid int(6) references t_dept(id)
);
-- 注意:在处理一对多关联关系时外键最好在多的一方
根据一查询多的一方(查询所有部门并将部门中所有的员工查询出来)
构建部门对象、员工对象:
// 部门对象
public class Dept {
private Integer id;
private String name;
// 对象 关系属性
private List<Emp> emps; //员工
// 为了不占用太大的篇幅,get、set、toString方法就不复制了,但是这些方法是有的
get,set,toString...
}
// 员工对象
public class Emp {
private Integer id;
private String name;
private Integer age;
private Date bir;
// 为了不占用太大的篇幅,get、set、toString方法就不复制了,但是这些方法是有的
get,set,toString...
}
构建DeptDAO接口,并定义查询所有部门并将每个部门的员工信息查询出来的方法:
public interface DeptDAO {
// 查询所有部门并将每个部门的员工信息查询出来
List<Dept> queryAll();
}
创建DeptDAO对应的mapper配置文件:
<mapper namespace="com.baizhi.dao.DeptDAO">
<!--resultMap-->
<resultMap id="deptMap" type="com.baizhi.eneity.Dept">
<!--封装部门信息-->
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--封装员工信息 如果是一对一用association 但是如果一对多,员工有多个用collection标签-->
<!--collection 用来处理一对多关联关系时的标签
property :封装的关系属性名(关系名,也就是对象的名字,在java中用对象表示关系)
javaType:关系属性类型(类的名字)
ofType:用来书写关系属性中泛型的类型(也就是List结合中封装的类的类型)
-->
<collection property="emps" javaType="java.util.List" ofType="com.baizhi.eneity.Emp">
<id column="eid" property="id"/>
<result column="ename" property="name"/>
<result column="age" property="age"/>
<result column="bir" property="bir"/>
</collection>
</resultMap>
<!--查询所有部门-->
<select id="queryAll" resultMap="deptMap">
select
d.id,
d.name,
e.id eid,
e.name ename,
e.age,
e.bir
from
t_dept d
left join t_emp e on d.id = e.deptid;
</select>
</mapper>
最后要在主配置文件mybatis-config.xml中注册一下mapper文件:
执行查询操作的java代码:
// 查询所有
@Test
public void testQueryAll() throws IOException {
SqlSession sqlSession = MybatisUtil.getSqlSession();
DeptDAO deptDAO = sqlSession.getMapper(DeptDAO.class);
deptDAO.queryAll().forEach(dept -> {
System.out.println("部门信息:====>" + dept);
dept.getEmps().forEach(emp -> {
System.out.println(" 员工信息:====>" + emp);
});
System.out.println("---------------------");
});
MybatisUtil.close(sqlSession);
}
结果:
查询员工并查询每个员工的部门
创建EmpDAO接口:
public interface EmpDAO {
// 查询所有员工并查询每个员工的部门
List<Emp> queryAll();
}
在Emp类中添加一个dept对象表示关系:
创建对应的mapper配置文件:
<mapper namespace="com.baizhi.dao.EmpDAO">
<resultMap id="empMap" type="com.baizhi.eneity.Emp">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
<result column="bir" property="bir"/>
<!--封装部门信息-->
<association property="dept" javaType="com.baizhi.eneity.Dept">
<id column="did" property="id"/>
<result column="dname" property="name"/>
</association>
</resultMap>
<select id="queryAll" resultMap="empMap">
select
e.id, e.name, e.age, e.bir,
d.id did, d.name dname
from t_emp e
left join t_dept d
on e.deptid = d.id
</select>
</mapper>
在主配置文件mybatis-config.xml中注册mapper配置文件:
查询所有员工并查询员工所在部门的java代码:
// queryAll
@Test
public void testQueryAll() throws IOException {
SqlSession sqlSession = MybatisUtil.getSqlSession();
EmpDAO empDAO = sqlSession.getMapper(EmpDAO.class);
empDAO.queryAll().forEach(emp -> {
System.out.println("员工信息:" + emp + " " + "部门信息:" + emp.getDept());
});
MybatisUtil.close(sqlSession);
}
3. 多对多关联关系处理
学生和课程关系是多对多关系
数据库中的表:
-- 学生表
create table t_student(
id int(6) primary key auto_increment,
name varchar(2)
);
-- 课程表
create table t_course(
id int(6) primary key auto_increment,
name varchar(2)
);
-- 中间表
create table t_student_course(
id int(6) primary key auto_increment,
sid int(6) references t_student(id),
cid int(6) references t_course(id)
);
java中的学生类、课程类:
// 学生类
public class Student {
private Integer id;
private String name;
// 关系属性 课程 选择哪些课
private List<Course> courses;
// 为了不占用太大的篇幅,get、set、toString方法就不复制了,但是这些方法是有的
get,set,toString...
}
// 课程类
public class Course {
private Integer id;
private String name;
// 关系属性 当前课程被哪些学生选择
private List<Student> students;
// 为了不占用太大的篇幅,get、set、toString方法就不复制了,但是这些方法是有的
get,set,toString...
}
用学生的id查询学生的信息并查询该学生的课程信息
创建StudentDAO接口:
public interface StudentDAO {
// 查询学生信息并查询所选课程
Student queryById(Integer id);
}
创建对应的mapper配置文件:
<mapper namespace="com.baizhi.dao.StudentDAO">
<resultMap id="studentMap" type="com.baizhi.eneity.Student">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--关系属性 多-->
<collection property="courses" javaType="java.util.List" ofType="com.baizhi.eneity.Course">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</collection>
</resultMap>
<!--queryById-->
<select id="queryById" parameterType="Integer" resultMap="studentMap">
select
s.id, s.name,
c.id cid, c.name cname
from t_student s
left join t_student_course tc
on s.id = tc.sid
left join t_course c
on tc.cid = c.id
where s.id = #{id}
</select>
</mapper>
在主配置文件mybatis-config.xml中注册:
执行的由id查询操作的代码:
@Test
public void testQueryById() throws IOException {
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
Student student = studentDAO.queryById(11);
System.out.println("学生信息:" + student);
student.getCourses().forEach(course -> {
System.out.println(" 课程信息:" + course);
});
MybatisUtil.close(sqlSession);
}
结果: