第九节:MyBatis之接口代理实现类、动态SQL拼接、分页插件、多表操作
一. 接口代理实现Dao
1. 背景
在这之前调用方法是通过硬编码的形式,直接映射到xml文件中的方法,比如:
List<Student> list = sqlSession.selectList("StudentMapper.selectAll");
调用的是StudentMapper.xml文件中的selectAll方法,很不友好
解决方案:
引出接口代理的方式,定义一个接口,声明方法和xml中相同,然后可以直接调用接口中的方法,内部映射通过mybatis实现。
2. 实现规范
(1) Mapper.xml文件中的namespace与mapper接口的全限定名相同
(2) Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
(3) Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
(4) Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
3. 代码分享
核心配置文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?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> <!--<typeAlias type="com.ypf.bean.Student" alias="student"/>--> <!-- 全局别名通用配置 --> <package name="com.ypf.bean"/> </typeAliases> <!--集成分页助手插件--> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins> <!--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属性指定映射配置文件的名称 --> <mapper resource="StudentMapper.xml"/> </mappers> </configuration>
映射配置文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="UTF-8" ?> <!--MyBatis的DTD约束--> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- mapper:核心根标签 namespace属性:名称空间 --> <mapper namespace="com.ypf.dao.StudentDao"> <!-- select:查询功能的标签 id属性:唯一标识 resultType属性:指定结果映射对象类型 parameterType属性:指定参数映射对象类型 --> <select id="selectAll" resultType="student"> SELECT * FROM student </select> <select id="selectById" resultType="student" parameterType="int"> SELECT * FROM student WHERE id = #{id} </select> <insert id="insert" parameterType="student"> INSERT INTO student VALUES (#{id},#{name},#{age}) </insert> <update id="update" parameterType="student"> UPDATE student SET name = #{name},age = #{age} WHERE id = #{id} </update> <delete id="delete" parameterType="int"> DELETE FROM student WHERE id = #{id} </delete> <!-- 单独把select语句抽离出来,供后面调用 --> <sql id="select">SELECT * FROM student</sql> <select id="selectCondition" resultType="student" parameterType="student"> <include refid="select"/> <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> <select id="selectByIds" resultType="student" parameterType="list"> <include refid="select"/> <where> <foreach collection="list" open="id IN (" close=")" item="id" separator=","> #{id} </foreach> </where> </select> </mapper>
代理接口 (上面的映射配置文件中的namespace要设为:com.ypf.dao.StudentDao)
package com.ypf.dao; import com.ypf.bean.Student; import java.util.List; public interface StudentDao { //查询全部 public abstract List<Student> selectAll(); //根据id查询 public abstract Student selectById(Integer id); //新增数据 public abstract Integer insert(Student stu); //修改数据 public abstract Integer update(Student stu); //删除数据 public abstract Integer delete(Integer id); }
测试方法
核心:获取代理对象,然后调用方法
StudentDao sDao=sqlSession.getMapper(StudentDao.class); int result=sDao.delete(5);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.ypf.test; import com.ypf.bean.Student; import com.ypf.dao.StudentDao; 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 StudentTest1 { /* 删除功能 */ @Test public void delete() throws Exception{ //1.加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //SqlSession sqlSession = sqlSessionFactory.openSession(true); //4.获取StudentDao实现类对象,并调用相关方法 StudentDao sDao=sqlSession.getMapper(StudentDao.class); int result=sDao.delete(5); //5.提交事务 sqlSession.commit(); //6.处理结果 System.out.println(result); //7.释放资源 sqlSession.close(); is.close(); } /* 修改功能 */ @Test public void update() throws Exception{ //1.加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //SqlSession sqlSession = sqlSessionFactory.openSession(true); //4.获取StudentDao实现类对象,并调用相关方法 Student stu = new Student(5,"周七",37); StudentDao sDao=sqlSession.getMapper(StudentDao.class); int result=sDao.update(stu); //5.提交事务 sqlSession.commit(); //6.处理结果 System.out.println(result); //7.释放资源 sqlSession.close(); is.close(); } /* 新增功能 */ @Test public void insert() throws Exception{ //1.加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 //SqlSession sqlSession = sqlSessionFactory.openSession(); SqlSession sqlSession = sqlSessionFactory.openSession(true); //设为true,表示自动提交事务,后面则不需要sqlSession.commit了 //4.获取StudentDao实现类对象,并调用相关方法 Student stu = new Student(5,"周七",27); StudentDao sDao=sqlSession.getMapper(StudentDao.class); int result = sDao.insert( stu); //5.提交事务 //sqlSession.commit(); //6.处理结果 System.out.println(result); //7.释放资源 sqlSession.close(); is.close(); } /* 根据id查询 */ @Test public void selectById() throws Exception{ //1.加载核心配置文件 InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml"); //2.获取SqlSession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //3.通过工厂对象获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //4.获取StudentDao实现类对象,并调用相关方法 StudentDao sDao=sqlSession.getMapper(StudentDao.class); Student stu = sDao.selectById(3); //5.处理结果 System.out.println(stu); //6.释放资源 sqlSession.close(); is.close(); } /* 查询全部 */ @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 sqlSession = sqlSessionFactory.openSession(); //4.获取StudentDao实现类对象,并调用相关方法 StudentDao sDao=sqlSession.getMapper(StudentDao.class); List<Student> list=sDao.selectAll(); //5.处理结果 for (Student stu : list) { System.out.println(stu); } //7.释放资源 sqlSession.close(); is.close(); } }
4. 源码分析
(1). 代理对象如何生成的?
通过动态代理开发模式,我们只编写一个接口,不写实现类,我们通过 getMapper() 方法最终获取到 org.apache.ibatis.binding.MapperProxy 代理对象,然后执行功能,而这个代理对象正是 MyBatis 使用了 JDK 的动态代理技术,帮助我们生成了代理实现类对象。从而可以进行相关持久化操作。
(2). 分析方法是如何执行的?
动态代理实现类对象在执行方法的时候最终调用了 mapperMethod.execute() 方法,这个方法中通过 switch 语句根据操作类型来判断是新增、修改、删除、查询操作,最后一步回到了 MyBatis 最原生的 SqlSession 方式来执行增删改查。
二. 动态SQL拼接
1. 动态SQL之IF
<where>:条件标签。如果有动态条件,则使用该标签代替 where 关键字。 <if>:条件判断标签。 <if test=“条件判断”> 查询条件拼接 </if>
xml代码
<!-- 单独把select语句抽离出来,供后面调用 --> <sql id="select">SELECT * FROM student</sql> <select id="selectCondition" resultType="student" parameterType="student"> <include refid="select"/> <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>
调用:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Test public void selectByIds() 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.获取StudentDao实现类对象,并调用相关方法 StudentDao sDao=sqlSession.getMapper(StudentDao.class); List<Integer> ids = new ArrayList<>(); ids.add(1); ids.add(2); ids.add(3); //5.调用实现类的方法,接收结果 List<Student> list = sDao.selectByIds(ids); //6.处理结果 for (Student student : list) { System.out.println(student); } //7.释放资源 sqlSession.close(); is.close(); }
2. 动态SQL之 foreach
<foreach>:循环遍历标签。适用于多个参数或者的关系。 <foreach collection=“”open=“”close=“”item=“”separator=“”> 获取参数 </foreach>
xml代码
<select id="selectByIds" resultType="student" parameterType="list"> <include refid="select"/> <where> <foreach collection="list" open="id IN (" close=")" item="id" separator=","> #{id} </foreach> </where> </select>
调用:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Test public void selectCondition() 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.获取StudentDao实现类对象,并调用相关方法 StudentDao sDao=sqlSession.getMapper(StudentDao.class); Student stu = new Student(); stu.setId(2); stu.setName("李四"); //stu.setAge(24); //5.调用实现类的方法,接收结果 List<Student> list = sDao.selectCondition(stu); //6.处理结果 for (Student student : list) { System.out.println(student); } //7.释放资源 sqlSession.close(); is.close(); }
三. 分页插件
1. 简介
在企业级开发中,分页也是一种常见的技术。而目前使用的 MyBatis 是不带分页功能的,如果想实现分页的 功能,需要我们手动编写 LIMIT 语句。但是不同的数据库实现分页的 SQL 语句也是不同的,所以手写分页 成本较高。这个时候就可以借助分页插件来帮助我们实现分页功能。
PageHelper:第三方分页助手。将复杂的分页操作进行封装,从而让分页功能变得非常简单。
2. 使用
(1). 通过maven引入相关jar包
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.1</version> </dependency> <dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>4.1</version> </dependency>
(2). 核心配置文件中添加下面引用
<!--集成分页助手插件--> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
(3). 直接测试使用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@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.获取StudentDao接口的实现类对象 StudentDao mapper = sqlSession.getMapper(StudentDao.class); //通过分页助手来实现分页功能 // 第一页:显示2条数据 PageHelper.startPage(1, 2); // 第二页:显示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(); }
3. 总结
1. PageHelper:分页助手功能类。 2. startPage():设置分页参数 3. PageInfo:分页相关参数功能类。 4. getTotal():获取总条数 5. getPages():获取总页数 6. getPageNum():获取当前页 7. getPageSize():获取每页显示条数 8. getPrePage():获取上一页 9. getNextPage():获取下一页 10. isIsFirstPage():获取是否是第一页 11. isIsLastPage():获取是否是最后一页
四. 多表操作
1. 数据表准备
(1). 1对1:在任意一方建立外键,关联对方的主键 。 (人和身份证,一个人只有一个身份证)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
CREATE TABLE person( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT ); INSERT INTO person VALUES (NULL,'张三',23); INSERT INTO person VALUES (NULL,'李四',24); INSERT INTO person VALUES (NULL,'王五',25); CREATE TABLE card( id INT PRIMARY KEY AUTO_INCREMENT, number VARCHAR(30), pid INT, CONSTRAINT cp_fk FOREIGN KEY (pid) REFERENCES person(id) ); INSERT INTO card VALUES (NULL,'12345',1); INSERT INTO card VALUES (NULL,'23456',2); INSERT INTO card VALUES (NULL,'34567',3);
(2). 1对多:在多的一方建立外键,关联一的一方的主键。 (班级和学生,一个班级可以有多个学生)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
CREATE TABLE classes( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) ); INSERT INTO classes VALUES (NULL,'一班'); INSERT INTO classes VALUES (NULL,'二班'); CREATE TABLE student( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(30), age INT, cid INT, CONSTRAINT cs_fk FOREIGN KEY (cid) REFERENCES classes(id) ); INSERT INTO student VALUES (NULL,'张三',23,1); INSERT INTO student VALUES (NULL,'李四',24,1); INSERT INTO student VALUES (NULL,'王五',25,2); INSERT INTO student VALUES (NULL,'赵六',26,2);
(3). 多对多:借助中间表,中间表至少两个字段,分别关联两张表的主键。(学生和课程,一个学生可以选择多门课程、一个课程也可以被多个学生所选择)
保留上面的student表,新增下面:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
CREATE TABLE course( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) ); INSERT INTO course VALUES (NULL,'语文'); INSERT INTO course VALUES (NULL,'数学'); CREATE TABLE stu_cr( id INT PRIMARY KEY AUTO_INCREMENT, sid INT, cid INT, CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id), CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id) ); INSERT INTO stu_cr VALUES (NULL,1,1); INSERT INTO stu_cr VALUES (NULL,1,2); INSERT INTO stu_cr VALUES (NULL,2,1); INSERT INTO stu_cr VALUES (NULL,2,2);
2. 一对一
映射配置文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?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.ypf.dao.StudentDao"> <!--配置字段和实体对象属性的映射关系--> <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="selectOneToOne" resultMap="oneToOne"> SELECT c.id cid,number,pid,NAME,age FROM card c,person p WHERE c.pid=p.id </select> </mapper>
代理类
public interface StudentDao { //1对1 public abstract List<Card> selectOneToOne(); //1对多 public abstract List<Classes> selectoneToMany(); //多对多 public abstract List<Student> selectmanyToMany(); }
实体类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.ypf.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) { this.id = id; this.name = name; this.age = age; } 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.ypf.bean; 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.ypf.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.ypf.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.ypf.bean; 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 + '}'; } }
测试调用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//1对1测试 @Test public void selectOneToOneTest() 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.获取StudentDao接口的实现类对象 StudentDao mapper = sqlSession.getMapper(StudentDao.class); //5.调用实现类的方法,接收结果 List<Card> list = mapper.selectOneToOne(); //6.处理结果 for (Card c : list) { System.out.println(c); } //7.释放资源 sqlSession.close(); is.close(); }
配置总结
<resultMap>:配置字段和对象属性的映射关系标签。 id 属性:唯一标识 type 属性:实体对象类型 <id>:配置主键映射关系标签。 <result>:配置非主键映射关系标签。 column 属性:表中字段名称 property 属性: 实体对象变量名称 <association>:配置被包含对象的映射关系标签。 property 属性:被包含对象的变量名 javaType 属性:被包含对象的数据类型
3. 一对多
映射配置文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?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.ypf.dao.StudentDao"> <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="selectoneToMany" 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>
代理类:同上
实体类:同上
测试调用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//1对多测试 @Test public void selectoneToManyTest() 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.获取StudentDao接口的实现类对象 StudentDao mapper = sqlSession.getMapper(StudentDao.class); //5.调用实现类的方法,接收结果 List<Classes> classes = mapper.selectoneToMany(); //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(); }
配置总结
<resultMap>:配置字段和对象属性的映射关系标签。 id 属性:唯一标识 type 属性:实体对象类型 <id>:配置主键映射关系标签。 <result>:配置非主键映射关系标签。 column 属性:表中字段名称 property 属性: 实体对象变量名称 <collection>:配置被包含集合对象的映射关系标签。 property 属性:被包含集合对象的变量名 ofType 属性:集合中保存的对象数据类型
4. 多对多
映射配置文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?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.ypf.dao.StudentDao"> <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="selectmanyToMany" 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>
代理类:同上
实体类:同上
测试调用
@Test public void selectmanyToManyTest() 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.获取StudentDao接口的实现类对象 StudentDao mapper = sqlSession.getMapper(StudentDao.class); //5.调用实现类的方法,接收结果 List<Student> students = mapper.selectmanyToMany(); //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(); }
配置总结
<resultMap>:配置字段和对象属性的映射关系标签。 id 属性:唯一标识 type 属性:实体对象类型 <id>:配置主键映射关系标签。 <result>:配置非主键映射关系标签。 column 属性:表中字段名称 property 属性: 实体对象变量名称 <collection>:配置被包含集合对象的映射关系标签。 property 属性:被包含集合对象的变量名 ofType 属性:集合中保存的对象数据类型
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。