Mybatis进阶
一,接口代理方式实现Dao层
1,实现规则介绍
-
传统方式实现 Dao 层,我们既要写接口,还要写实现类。而 MyBatis 框架可以帮助我们省略编写 Dao 层接 口实现类的步骤。
-
程序员只需要编写接口,由 MyBatis 框架根据接口的定义来创建该接口的动态代理对象。
-
实现规则
映射配置文件中的名称空间(namespace)必须和 Dao 层接口的全类名相同。
eg:
<mapper namespace="com.itheima.mapper.StudentMapper">
映射配置文件中的增删改查标签的 id 属性必须和 Dao 层接口的方法名相同。
映射配置文件中的增删改查标签的 parameterType 属性必须和 Dao 层接口方法的参数相同。
映射配置文件中的增删改查标签的 resultType 属性必须和 Dao 层接口方法的返回值相同。
2,代码实现
<mapper namespace="com.itheima.mapper.StudentMapper">
<sql id="select" >SELECT * FROM student</sql>
<select id="selectAll" resultType="student">
<include refid="select"/>
</select>
import com.itheima.bean.Student;
import com.itheima.mapper.StudentMapper;
import com.itheima.service.StudentService;
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;
import java.util.List;
/*
业务层实现类
*/
public class StudentServiceImpl implements StudentService {
@Override
public List<Student> selectAll() {
List<Student> list = null;
SqlSession sqlSession = null;
InputStream is = null;
try{
//1.加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//4.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();
//5.通过实现类对象调用方法,接收结果
list = mapper.selectAll();
} catch (Exception e) {
} finally {
//6.释放资源
if(sqlSession != null) {
sqlSession.close();
}
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//7.返回结果
return list;
}
3,源码分析
- 分析动态代理对象如何生成的?
- 通过动态代理开发模式,我们只编写一个接口,不写实现类,我们通过 getMapper() 方法最终获取到 org.apache.ibatis.binding.MapperProxy 代理对象,然后执行功能,而这个代理对象正是 MyBatis 使用了 JDK 的动态代理技术,帮助我们生成了代理实现类对象。从而可以进行相关持久化操作。
- 分析方法是如何执行的?
- 动态代理实现类对象在执行方法的时候最终调用了 mapperMethod.execute() 方法,这个方法中通过 switch 语句根据操作类型来判断是新增、修改、删除、查询操作,最后一步回到了 MyBatis 最原生的 SqlSession 方式来执行增删改查。
4,小结
- 接口代理方式可以让我们只编写接口即可,而实现类对象由 MyBatis 生成。
- 实现规则
- 映射配置文件中的名称空间必须和Dao层接口的全类名相同。
- 映射配置文件中的增删改查标签的id属性必须和Dao层接口的方法名相同。
- 映射配置文件中的增删改查标签的parameterType属性必须和Dao层接口方法的参数相同。
- 映射配置文件中的增删改查标签的resultType属性必须和Dao层接口方法的返回值相同。
- 获取动态代理对象
- SqlSession功能类中的getMapper()方法。
二,映射配置文件—动态SQL
1,动态sql的介绍
-
MyBatis 映射配置文件中,前面我们的 SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL 就是 动态变化的,此时在前面学习的 SQL 就不能满足要求了。
-
比如多条件查询
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gor2Uc3d-1592649503367)(C:\Users\HUANGHAI\AppData\Roaming\Typora\typora-user-images\1592234657301.png)]
因为sql语句写死了,只能三个条件都有才能查询,不能说我给你两个条件,你就根据两个条件来查,给你一个,你就根据一个来查。
要达成这些就需要动态SQL,
-
动态 SQL 标签
:条件判断标签。
:循环遍历标签。
2,if标签的使用
-
:条件标签。如果有动态条件,则使用该标签代替 where 关键字。
:条件判断标签。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7SiK4bxW-1592649503370)(C:\Users\HUANGHAI\AppData\Roaming\Typora\typora-user-images\1592315346791.png)]
where 标签可以自动去除多余的and
<select id="selectCondition" resultType="student" parameterType="student">
SELECT * FROM student
<where>
<if test="id != null" >
id = #{id}
</if>
<if test="name != null">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
3,foreach标签的使用
-
:循环遍历标签。适用于多个参数或者的关系。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lLngoEbu-1592649503371)(C:\Users\HUANGHAI\AppData\Roaming\Typora\typora-user-images\1592315805693.png)]
-
属性
collection:我们要遍历的参数容器类型,(list-集合,array-数组)。
open:开始的 SQL 语句。
close:结束的 SQL 语句。
item:参数变量名。
separator:参数分隔符
<!--多id或者查询--><!--select * from student where id in (1,2,3)--> <select id="selectByIds" resultType="student" parameterType="list"> SELECT * FROM student <where> <foreach collection="list" open="id IN (" close=")" item="id" separator=","> #{id} </foreach> </where> </select>
4,sql片段的抽取
我们可以将一些重复性的 SQL 语句进行抽取,以达到复用的效果。
:抽取 SQL 语句标签。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yvYd73SF-1592649503373)(C:\Users\HUANGHAI\AppData\Roaming\Typora\typora-user-images\1592316255044.png)]
- 使用方法
:引入 SQL 片段标签。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vXKMAawm-1592649503375)(C:\Users\HUANGHAI\AppData\Roaming\Typora\typora-user-images\1592316301605.png)]
5,动态sql的小结
-
动态 SQL 指的就是 SQL 语句可以根据条件或者参数的不同进行动态的变化。
:条件标签。
:条件判断的标签。
:循环遍历的标签。
:抽取 SQL 片段的标签。
:引入 SQL 片段的标签。
三,核心配置文件—分页插件
1,分页插件的介绍
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CSOoD0a0-1592649503377)(C:\Users\HUANGHAI\AppData\Roaming\Typora\typora-user-images\1592316880248.png)]
-
回顾mysql里面的分页查询:当前页(当前页-1*每页显示条数),每页显示条数。eg:第二页 select * from student limit 3,3
-
分页可以将很多条结果进行分页显示。
-
如果当前在第一页,则没有上一页。如果当前在最后一页,则没有下一页。
-
需要明确当前是第几页,这一页中显示多少条结果。
-
-
在企业级开发中,分页也是一种常见的技术。而目前使用的 MyBatis 是不带分页功能的,如果想实现分页的 功能,需要我们手动编写 LIMIT 语句但是不同的数据库实现分页的 SQL 语句也是不同的,所以手写分页 成本较高。这个时候就可以借助分页插件来帮助我们实现分页功能。
- PageHelper:第三方分页助手。将复杂的分页操作进行封装,从而让分页功能变得非常简单。
2,分页插件的使用
- 分页插件实现步骤
- 导入 jar 包。
- 在核心配置文件中集成分页助手插件。
- 在测试类中使用分页助手相关 API 实现分页功能。
3,分页参数的获取
-
PageInfo:封装分页相关参数的功能类。 .
-
核心方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ZZR1SDr-1592649503380)(C:\Users\HUANGHAI\AppData\Roaming\Typora\typora-user-images\1592320225132.png)]
<!--集成分页助手插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.bean.Student;
import com.itheima.mapper.StudentMapper;
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 org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class Test01 {
@Test
public void selectPaging() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//通过分页助手来实现分页功能
// 第一页:显示3条数据
//PageHelper.startPage(1,3);
// 第二页:显示3条数据
//PageHelper.startPage(2,3);
// 第三页:显示3条数据
PageHelper.startPage(3,3);
//5.调用实现类的方法,接收结果
List<Student> list = mapper.selectAll();
//6.处理结果
for (Student student : list) {
System.out.println(student);
}
//获取分页相关参数
PageInfo<Student> info = new PageInfo<>(list);
System.out.println("总条数:" + info.getTotal());
System.out.println("总页数:" + info.getPages());
System.out.println("当前页:" + info.getPageNum());
System.out.println("每页显示条数:" + info.getPageSize());
System.out.println("上一页:" + info.getPrePage());
System.out.println("下一页:" + info.getNextPage());
System.out.println("是否是第一页:" + info.isIsFirstPage());
System.out.println("是否是最后一页:" + info.isIsLastPage());
//7.释放资源
sqlSession.close();
is.close();
}
}
4,分页插件的小结
-
分页:可以将很多条结果进行分页显示。
-
分页插件 jar 包:pagehelper-5.1.10.jar 和jsqlparser-3.1.jar
-
:在核心配置文件里面集成插件标签。
-
分页助手相关 API
-
PageHelper:分页助手功能类。
startPage():设置分页参数
- PageInfo:分页相关参数功能类。
getTotal():获取总条数
getPages():获取总页数
getPageNum():获取当前页
getPageSize():获取每页显示条数
getPrePage():获取上一页
getNextPage():获取下一页
isIsFirstPage():获取是否是第一页
isIsLastPage():获取是否是最后一页
四,多表操作
1,多表模型的介绍
-
我们之前学习的都是基于单表操作的,而实际开发中,随着业务难度的加深,肯定需要多表操作的。
- 多表模型分类
一对一:在任意一方建立外键,关联对方的主键。 eg:一个人一身份证
一对多:在多的一方建立外键,关联一的一方的主键。 eg:一个班多个学生
多对多:借助中间表,中间表至少两个字段,分别关联两张表的主键。
eg:多个学生选择多个课程,互相是多对多
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4gmjaBPk-1592649503384)(C:\Users\HUANGHAI\AppData\Roaming\Typora\typora-user-images\1592384565792.png)]
2,一对一的数据准备
card表
public class Card {
private Integer id; //主键id
private String number; //身份证号
private Person p; //所属人的对象
public Card() {
}
public Card(Integer id, String number, Person p) {
this.id = id;
this.number = number;
this.p = p;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Person getP() {
return p;
}
public void setP(Person p) {
this.p = p;
}
@Override
public String toString() {
return "Card{" +
"id=" + id +
", number='" + number + '\'' +
", p=" + p +
'}';
}
}
person表
public class Person {
private Integer id; //主键id
private String name; //人的姓名
private Integer age; //人的年龄
public Person() {
}
public Person(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
接口
package com.itheima.table01;
import com.itheima.bean.Card;
import java.util.List;
public interface OneToOneMapper {
//查询全部
public abstract List<Card> selectAll();
}
映射文件
<?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="com.itheima.table01.OneToOneMapper">
<!--配置字段和实体对象属性的映射关系-->
<resultMap id="oneToOne" type="card">
<id column="cid" property="id" />
<result column="number" property="number" />
<!--
association:配置被包含对象的映射关系
property:被包含对象的变量名
javaType:被包含对象的数据类型
-->
<association property="p" javaType="person">
<id column="pid" property="id" />
<result column="name" property="name" />
<result column="age" property="age" />
</association>
</resultMap>
<select id="selectAll" resultMap="oneToOne">
SELECT c.id cid,number,pid,NAME,age FROM card c,person p WHERE c.pid=p.id
</select>
</mapper>
核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束-->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration 核心根标签-->
<configuration>
<!--引入数据库连接的配置文件-->
<properties resource="jdbc.properties"/>
<!--配置LOG4J-->
<settings>
<setting name="logImpl" value="log4j"/>
</settings>
<!--起别名-->
<typeAliases>
<package name="com.itheima.bean"/>
</typeAliases>
<!--environments配置数据库环境,环境可以有多个。default属性指定使用的是哪个-->
<environments default="mysql">
<!--environment配置数据库环境 id属性唯一标识-->
<environment id="mysql">
<!-- transactionManager事务管理。 type属性,采用JDBC默认的事务-->
<transactionManager type="JDBC"></transactionManager>
<!-- dataSource数据源信息 type属性 连接池-->
<dataSource type="POOLED">
<!-- property获取数据库连接的配置信息 -->
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<!-- mappers引入映射配置文件 -->
<mappers>
<mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"/>
<mapper resource="com/itheima/one_to_many/OneToManyMapper.xml"/>
<mapper resource="com/itheima/many_to_many/ManyToManyMapper.xml"/>
</mappers>
</configuration>
3,一对一的功能实现
:配置字段和对象属性的映射关系标签。
-
id 属性:唯一标识
-
type 属性:代表要给哪个实体对象配置映射关系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o0wREebj-1592649503387)(C:\Users\HUANGHAI\AppData\Roaming\Typora\typora-user-images\1592442845723.png)]
:配置主键映射关系标签。
-
column 属性:代表表中字段名称
-
property 属性: 实体对象变量名称
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3a9rTjvy-1592649503388)(C:\Users\HUANGHAI\AppData\Roaming\Typora\typora-user-images\1592442805386.png)]
:配置非主键映射关系标签。
-
column 属性:表中字段名称
-
property 属性: 实体对象变量名称
<result column="number" property="number" />
:配置被包含对象的映射关系标签。eg
在card表中,被包含的对象是person对象
-
property 属性:被包含对象的变量名
-
javaType 属性:被包含对象的实际数据类型
<association property="p" javaType="person"> <id column="pid" property="id" /> <result column="name" property="name" /> <result column="age" property="age" /> </association>
一对一映射配置文件总结
<?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"> <!--这个名称空间就是OneToOneMapper接口的全类名--> <mapper namespace="com.itheima.table01.OneToOneMapper"> <!--配置字段和实体对象属性的映射关系--> <resultMap id="oneToOne" type="card"> <!--type字段代表给哪个实体对象配置映射关系--> <id column="cid" property="id" /> <result column="number" property="number" /> <!-- association:配置被包含对象的映射关系 property:被包含对象的变量名 javaType:被包含对象的数据类型 --> <association property="p" javaType="person"> <id column="pid" property="id" /> <result column="name" property="name" /> <result column="age" property="age" /> </association> </resultMap> <!--resultmap属性是多表操作的结果封装,需要上面单独标签细化--> <select id="selectAll" resultMap="oneToOne"> SELECT c.id cid,number,pid,NAME,age FROM card c,person p WHERE c.pid=p.id </select> </mapper>
4,一对多的数据准备
5,一对多的功能实现
班级类
package com.itheima.bean;
import java.util.List;
public class Classes {
private Integer id; //主键id
private String name; //班级名称
private List<Student> students; //班级中所有学生对象
public Classes() {
}
public Classes(Integer id, String name, List<Student> students) {
this.id = id;
this.name = name;
this.students = students;
}
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 List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
@Override
public String toString() {
return "Classes{" +
"id=" + id +
", name='" + name + '\'' +
", students=" + students +
'}';
}
}
学生类
package com.itheima.bean;
import java.util.List;
public class Student {
private Integer id; //主键id
private String name; //学生姓名
private Integer age; //学生年龄
private List<Course> courses; // 学生所选择的课程集合
public Student() {
}
public Student(Integer id, String name, Integer age, List<Course> courses) {
this.id = id;
this.name = name;
this.age = age;
this.courses = courses;
}
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
接口
package com.itheima.table02;
import com.itheima.bean.Classes;
import java.util.List;
public interface OneToManyMapper {
//查询全部
public abstract List<Classes> selectAll();
}
核心配置文件
<mappers>
<mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"/>
<mapper resource="com/itheima/one_to_many/OneToManyMapper.xml"/>
<mapper resource="com/itheima/many_to_many/ManyToManyMapper.xml"/>
</mappers>
映射配置文件
<?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="com.itheima.table02.OneToManyMapper">
<resultMap id="oneToMany" type="classes">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
<!--
collection:配置被包含的集合对象映射关系
property:被包含对象的变量名
ofType:被包含对象的实际数据类型
-->
<collection property="students" ofType="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="sage" property="age"/>
</collection>
</resultMap>
<!-- 把这些结果集的字段一一映射到上面一一指定完-->
<select id="selectAll" resultMap="oneToMany">
SELECT c.id cid,c.name cname,s.id sid,s.name sname,s.age sage FROM classes c,student s WHERE c.id=s.cid
</select>
</mapper>
测试类
package com.itheima.table02;
import com.itheima.bean.Classes;
import com.itheima.bean.Student;
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 org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class Test01 {
@Test
public void selectAll() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.获取OneToManyMapper接口的实现类对象
OneToManyMapper mapper = sqlSession.getMapper(OneToManyMapper.class);
//5.用自己接口的实现类调用方法,接收结果
List<Classes> classes = mapper.selectAll();
//6.处理结果
for (Classes cls : classes) {
System.out.println(cls.getId() + "," + cls.getName());
List<Student> students = cls.getStudents();
for (Student student : students) {
System.out.println("\t" + student);
}
}
//7.释放资源
sqlSession.close();
is.close();
}
}
-
:配置字段和对象属性的映射关系标签。
-
id 属性:唯一标识
-
type 属性:实体对象类型
:配置主键映射关系标签。
:配置非主键映射关系标签。
-
column 属性:表中字段名称
-
property 属性: 实体对象变量名称
:配置被包含集合对象的映射关系标签。
-
property 属性:被包含集合对象的变量名
-
ofType 属性:集合中保存的对象数据类型
-
6,多对多的数据准备
7,多对多的功能实现
课程表
package com.itheima.bean;
public class Course {
private Integer id; //主键id
private String name; //课程名称
public Course() {
}
public Course(Integer id, String name) {
this.id = id;
this.name = name;
}
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;
}
@Override
public String toString() {
return "Course{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
学生表
package com.itheima.bean;
import java.util.List;
public class Student {
private Integer id; //主键id
private String name; //学生姓名
private Integer age; //学生年龄
private List<Course> courses; // 学生所选择的课程集合
public Student() {
}
public Student(Integer id, String name, Integer age, List<Course> courses) {
this.id = id;
this.name = name;
this.age = age;
this.courses = courses;
}
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
接口
package com.itheima.table03;
import com.itheima.bean.Student;
import java.util.List;
public interface ManyToManyMapper {
//查询全部
public abstract List<Student> selectAll();
} //为什么选学生为集合,因为标准类学生里面包含课程
核心配置文件
<mappers>
<mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"/>
<mapper resource="com/itheima/one_to_many/OneToManyMapper.xml"/>
<mapper resource="com/itheima/many_to_many/ManyToManyMapper.xml"/>
</mappers>
映射配置文件
<?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="com.itheima.table03.ManyToManyMapper">
<resultMap id="manyToMany" type="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="sage" property="age"/>
<collection property="courses" ofType="course">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</collection>
</resultMap>
<!--把这些字段一一映射到上面-->
<select id="selectAll" resultMap="manyToMany">
SELECT sc.sid,s.name sname,s.age sage,sc.cid,c.name cname FROM student s,course c,stu_cr sc WHERE sc.sid=s.id AND sc.cid=c.id
</select>
</mapper>
测试类
package com.itheima.table03;
import com.itheima.bean.Course;
import com.itheima.bean.Student;
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 org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class Test01 {
@Test
public void selectAll() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.获取ManyToManyMapper接口的实现类对象
ManyToManyMapper mapper = sqlSession.getMapper(ManyToManyMapper.class);
//5.调用实现类的方法,接收结果
List<Student> students = mapper.selectAll();
//6.处理结果
for (Student student : students) {
System.out.println(student.getId() + "," + student.getName() + "," + student.getAge());
List<Course> courses = student.getCourses();
for (Course cours : courses) {
System.out.println("\t" + cours);
}
}
//7.释放资源
sqlSession.close();
is.close();
}
}
-
:配置字段和对象属性的映射关系标签。
-
id 属性:唯一标识
-
type 属性:实体对象类型
:配置主键映射关系标签。
:配置非主键映射关系标签。
-
column 属性:表中字段名称
-
property 属性: 实体对象变量名称
:配置被包含集合对象的映射关系标签。
-
property 属性:被包含集合对象的变量名
-
ofType 属性:集合中保存的对象数据类型
-
8,多表操作的小结
封装的主体对象都是由你自己在起始的标准类定义的,
eg
//标准类中想查询这个
private List<Course> courses;
//则接口中方法
public abstract List<Student> selectAll();
} //为什么选学生为集合,因为标准类学生里面包含课程
//映射文件中
<resultMap id="manyToMany" type="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="sage" property="age"/>
<collection property="courses" ofType="course">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</collection>
</resultMap>
<!--把这些字段一一映射到上面-->
<select id="selectAll" resultMap="manyToMany">
ResultType:单表查询
ResultMap:多表查询
cours : courses) {
System.out.println("\t" + cours);
}
}
//7.释放资源
sqlSession.close();
is.close();
}
}
- <resultMap>:配置字段和对象属性的映射关系标签。
- id 属性:唯一标识
- type 属性:实体对象类型
<id>:配置主键映射关系标签。
<result>:配置非主键映射关系标签。
- column 属性:表中字段名称
- property 属性: 实体对象变量名称
<collection>:配置被包含集合对象的映射关系标签。
- property 属性:被包含集合对象的变量名
- ofType 属性:集合中保存的对象数据类型
### 8,多表操作的小结
封装的主体对象都是由你自己在起始的标准类定义的,
eg
```xml
//标准类中想查询这个
private List<Course> courses;
//则接口中方法
public abstract List<Student> selectAll();
} //为什么选学生为集合,因为标准类学生里面包含课程
//映射文件中
<resultMap id="manyToMany" type="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="sage" property="age"/>
<collection property="courses" ofType="course">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</collection>
</resultMap>
<!--把这些字段一一映射到上面-->
<select id="selectAll" resultMap="manyToMany">
ResultType:单表查询
ResultMap:多表查询