打包⽅式:jar
依赖:mybatis依赖、mysql驱动依赖、junit依赖、logback依赖
配置⽂件:mybatis-config.xml、logback.xml、jdbc.properties
拷⻉⼯具类:SqlSessionUtil
1. 准备数据 103
1.1 创建数据库 103
⼀个班级对应多个学⽣。班级表:t_clazz。学⽣表:t_student
1.2 创建pojo:Student、Clazz 104
package com.powernode.mybatis.pojo;
//实体类 学生 pojo 104
/**
* 学生信息
*/
public class Student { // Student是多的一方
private Integer sid;
private String sname;
private Clazz clazz; // Clazz是一的一方。
@Override
public String toString() {
return "Student{" +
"sid=" + sid +
", sname='" + sname + '\'' +
", clazz=" + clazz +
'}';
}
public Clazz getClazz() {
return clazz;
}
public void setClazz(Clazz clazz) {
this.clazz = clazz;
}
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Student(Integer sid, String sname) {
this.sid = sid;
this.sname = sname;
}
public Student() {
}
}
package com.powernode.mybatis.pojo;
//实体类 班级 pojo 104
import java.util.List;
/**
* 班级信息
*/
public class Clazz {
private Integer cid;
private String cname;
public Clazz() {
}
public Clazz(Integer cid, String cname) {
this.cid = cid;
this.cname = cname;
}
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Clazz{" +
"cid=" + cid +
", cname='" + cname + '\'' +
'}';
}
}
2. 多对一映射实体类关系 105
多对一:
多的一方是: Student
一的一.方是: Clazz
2.1 怎么分主表和副表。 105
原则:谁在前谁是主表。
多对一: 多在前,那么多就是主表。
一对多:一-在前,那么一-就是主表。
2.2 多种⽅式,常⻅的包括三种: 106
● 第⼀种⽅式:⼀条SQL语句,级联属性映射。
● 第⼆种⽅式:⼀条SQL语句,association。
● 第三种⽅式:两条SQL语句,分步查询。(这种⽅式常⽤:优点⼀是可复⽤。优点⼆是⽀持懒加载。)
2.2.1 第⼀种⽅式:⼀条SQL语句,级联属性映射。 106
pojo类Student中添加⼀个属性:Clazz clazz; 表示学⽣关联的班级对象。
@Test
public void testselectById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.selectById(1);
System.out.println(student.getSid());
System.out.println(student.getSname());
System.out.println(student.getClazz().getCid());
System.out.println(student.getClazz().getCname());
//System.out.println(student);
sqlSession.close();
}
<!--这个标签的作用就是指定学生表t_stu和Java pojo Student的对应关系
多对一映射的第一种方式:一条SQL语句,级联属性映射。-->
<resultMap id="studentResultMap" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<result property="clazz.cid" column="cid"/>
<result property="clazz.cname" column="cname"/>
</resultMap>
<select id="selectById" resultMap="studentResultMap">
select
s.sid,s.sname,c.cid,c.cname
from
t_stu s left join t_clazz c on s.cid = c.cid
where
s.sid = #{sid}
</select>
2.2.2 第⼆种⽅式:⼀条SQL语句,association。 107
association:翻译为关联。一个Student对象关联一个Clazz对象
property:提供要映射的POJO类的属性名。
javaType:用来指定要映射的java类型。
<!--一条SQL语句,association。 107-->
<resultMap id="studentResultMapAssociation" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<!--
association:翻译为关联。一个Student对象关联一个Clazz对象
property:提供要映射的POJO类的属性名。
javaType:用来指定要映射的java类型。
-->
<association property="clazz" javaType="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
</association>
</resultMap>
<select id="selectByIdAssociation" resultMap="studentResultMapAssociation">
select
s.sid,s.sname,c.cid,c.cname
from
t_stu s left join t_clazz c on s.cid = c.cid
where
s.sid = #{sid}
</select>
//第二种方式 一条SQL语句,association 107
@Test
public void testSelectByIdAssociation(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.selectByIdAssociation(4);
System.out.println(student);
sqlSession.close();
}
2.2.3 第三种⽅式:两条SQL语句,分步查询。 108
(这种⽅式常⽤:优点⼀是可复⽤。优点⼆是⽀持懒加载。)
2.2.3.1 第一步: 108
根据学生的id查询学生的所有信息。这些信息当中含有班级id(cid)
StudentMapper
/**
* 这是多对一
* 分部查询第一步:先根据学生的sid查询学生的信息。 108
* @param sid
* @return
*/
Student selectByIdStep1(Integer sid);
其他位置不需要修改,只需要修改以及添加以下三处:
第⼀处:association中select位置填写sqlId即指定另外的第二步的sql语句的id。sqlId=namespace+id。其中column属性作为这条⼦sql语句的条件。
StudentMapper.xml
<resultMap id="studentResultMapByStep" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<association property="clazz"
select="com.powernode.mybatis.mapper.ClazzMapper.selectByIdStep2"
column="cid"
/>
</resultMap>
<select id="selectByIdStep1" resultMap="studentResultMapByStep">
select sid,sname,cid from t_stu where sid = #{sid}
</select>
com.powernode.mybatis.test
StudentMapperTest
//分部查询第一步:先根据学生的sid查询学生的信息。 108
//分步查询第二步:根据cid获取班级信息。 108
@Test
public void testSelectByIdStep1(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.selectByIdStep1(5);
//System.out.println(student);
// 懒加载 只需要看学生的名字 109
System.out.println(student.getSname());
// 程序执行到这里了,我想看看班级的名字
//System.out.println(student.getClazz().getCname());
sqlSession.close();
}
2.2.3.2 第⼆步: 108
com.powernode.mybatis.mapper
在ClazzMapper接⼝中添加⽅法
/**
* 这是多对一
* 分步查询第二步:根据cid获取班级信息。 108
* @param cid
* @return
*/
Clazz selectByIdStep2(Integer cid);
在ClazzMapper.xml⽂件中进⾏配置
<!--分步查询第二步:根据cid获取班级信息。 108-->
<select id="selectByIdStep2" resultType="Clazz">
select cid,cname from t_clazz where cid = #{cid}
</select>
3. 多对⼀延迟加载 109
3.1 分步查询的优点: 109
第一:复用性增强。可以重复利用。(大步拆成N多个小碎步。每一个小碎步更加可以重复利用。)
第二:采用这种分步查询,可以充分利用他们的延迟加载/懒加载机制。
3.2 什么是延迟加载(懒加载),有什么用? 109
延迟加载的核心原理是:用的时候再执行查询语句。不用的时候不查询。
作用:提高性能。尽可能的不查,或者说尽可能的少查。来提高效率。
3.2.1 在mybatis当中怎么开启延迟加载呢? 109
association标签中添加fetchType="lazy"
注意:默认情况下是没有开启延迟加载的。需要设置:fetchType="lazy"
这种在association标签中配置fetchType="lazy",是局部的设置,只对当前的association关联的sql语句起作用。
3.2.1.1 延迟加载的全局开关 109
在实际的开发中,大部分都是需要使用延迟加载的,所以建议开启全部的延迟加载机制:
在mybatis核心配置文件中添加全局配置:lazyLoadingEnabled=true
<settings>
<!--延迟加载的全局开关。默认值false不开启。 109-->
<!--什么意思:所有只要但凡带有分步的,都采用延迟加载。-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
实际开发中的模式:
把全局的延迟加载打开。
如果某一步不需要使用延迟加载,请设置:fetchType="eager"
3.2.2 例 109
要想⽀持延迟加载,⾮常简单,只需要在association标签中添加fetchType="lazy"即可。
修改StudentMapper.xml⽂件
我们现在只查询学⽣名字,修改测试程序:
<resultMap id="studentResultMapByStep" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<association property="clazz"
select="com.powernode.mybatis.mapper.ClazzMapper.selectByIdStep2"
column="cid"
fetchType="lazy"/>
</resultMap>
<select id="selectByIdStep1" resultMap="studentResultMapByStep">
select sid,sname,cid from t_stu where sid = #{sid}
</select>
@Test
public void testSelectByIdStep1(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.selectByIdStep1(5);
//System.out.println(student);
// 懒加载 只需要看学生的名字 109
System.out.println(student.getSname());
// 程序执行到这里了,我想看看班级的名字 109
//System.out.println(student.getClazz().getCname());
sqlSession.close();
}
如果后续需要使⽤到学⽣所在班级的名称,这个时候才会执⾏关联的sql语句,修改测试程序:
@Test
public void testSelectByIdStep1(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.selectByIdStep1(5);
//System.out.println(student);
// 懒加载 只需要看学生的名字 109
System.out.println(student.getSname());
// 程序执行到这里了,我想看看班级的名字 109
System.out.println(student.getClazz().getCname());
sqlSession.close();
}
通过以上的执⾏结果可以看到,只有当使⽤到班级名称之后,才会执⾏关联的sql语句,这就是延迟加载
4. 一对多 110
4.1 ⼀对多的实现通常包括两种实现⽅式: 111
4.1.1 第⼀种⽅式:collection
注意是ofType,表示“集合中的类型”。
ClazzMapper.xml
<resultMap id="clazzResultMap" type="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<!--一对多,这里是collection。collection是集合的意思。111-->
<!--ofType 属性用来指定集合当中的元素类型。-->
<collection property="stus" ofType="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
</collection>
</resultMap>
<select id="selectByCollection" resultMap="clazzResultMap">
select c.cid,c.cname,s.sid,s.sname from t_clazz c left join t_stu s on c.cid = s.cid where c.cid = #{cid}
</select>
ClazzMapperTest
//根据班级编号查询班级信息。 111
@Test
public void testSelectByCollection(){
SqlSession sqlSession = SqlSessionUtil.openSession();
ClazzMapper mapper = sqlSession.getMapper(ClazzMapper.class);
Clazz clazz = mapper.selectByCollection(1000);
System.out.println(clazz);
sqlSession.close();
}
4.1.2 第⼆种⽅式:分步查询 112
第一步
ClazzMapper
/**
* 这是一对多
* 分步查询。第一步:根据班级编号获取班级信息。 112
* @param cid 班级编号
* @return
*/
Clazz selectByStep1(Integer cid);
ClazzMapper.xml
<!--分步查询第一步:根据班级的cid获取班级信息。 112-->
<resultMap id="clazzResultMapStep" type="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<collection property="stus"
select="com.powernode.mybatis.mapper.StudentMapper.selectByCidStep2"
column="cid" fetchType="eager" />
</resultMap>
<select id="selectByStep1" resultMap="clazzResultMapStep">
select cid,cname from t_clazz where cid = #{cid}
</select>
ClazzMapperTest
//分步查询。第一步:根据班级编号获取班级信息。 112
@Test
public void testSelectByStep1(){
SqlSession sqlSession = SqlSessionUtil.openSession();
ClazzMapper mapper = sqlSession.getMapper(ClazzMapper.class);
Clazz clazz = mapper.selectByStep1(1000);
//System.out.println(clazz);
// 只访问班级名字。
System.out.println(clazz.getCname());
// 只有用到的时候才会去执行第二步SQL
//System.out.println(clazz.getStus());
sqlSession.close();
}
第二步
StudentMapper
/**
* 这是一对多
* 分布查询第二步
* 根据班级编号查询学生信息。 112
* @param cid
* @return
*/
List<Student> selectByCidStep2(Integer cid);
StudentMapper.xml
<select id="selectByCidStep2" resultType="Student">
select * from t_stu where cid = #{cid}
</select>
5. 代码汇总
main中com.powernode.mybatis.mapper
ClazzMapper
package com.powernode.mybatis.mapper;
import com.powernode.mybatis.pojo.Clazz;
//班级接口 104
public interface ClazzMapper {
/**
* 这是一对多
* 分步查询。第一步:根据班级编号获取班级信息。 112
* @param cid 班级编号
* @return
*/
Clazz selectByStep1(Integer cid);
/**
* 根据班级编号查询班级信息。 111
* @param cid
* @return
*/
Clazz selectByCollection(Integer cid);
/**
* 这是多对一
* 分步查询第二步:根据cid获取班级信息。 108
* @param cid
* @return
*/
Clazz selectByIdStep2(Integer cid);
}
StudentMapper
package com.powernode.mybatis.mapper;
import com.powernode.mybatis.pojo.Student;
import java.util.List;
//学生接口 104
public interface StudentMapper {
/**
* 这是一对多
* 分布查询第二步
* 根据班级编号查询学生信息。 112
* @param cid
* @return
*/
List<Student> selectByCidStep2(Integer cid);
/**
* 这是多对一
* 分部查询第一步:先根据学生的sid查询学生的信息。 108
* @param sid
* @return
*/
Student selectByIdStep1(Integer sid);
/**
* 一条SQL语句,association 107
* @param id
* @return
*/
Student selectByIdAssociation(Integer id);
/**
* 第⼀种⽅式:⼀条SQL语句,级联属性映射。 106
* 根据id获取学生信息。同时获取学生关联的班级信息。 106
* @param id 学生的id
* @return 学生对象,但是学生对象当中含有班级对象。
*/
Student selectById(Integer id);
}
ClazzMapper.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="com.powernode.mybatis.mapper.ClazzMapper">
<!--这是一对多 分步查询第一步:根据班级的cid获取班级信息。 112-->
<resultMap id="clazzResultMapStep" type="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<collection property="stus"
select="com.powernode.mybatis.mapper.StudentMapper.selectByCidStep2"
column="cid" fetchType="eager" />
</resultMap>
<select id="selectByStep1" resultMap="clazzResultMapStep">
select cid,cname from t_clazz where cid = #{cid}
</select>
<resultMap id="clazzResultMap" type="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<!--一对多,这里是collection。collection是集合的意思。111-->
<!--ofType 属性用来指定集合当中的元素类型。-->
<collection property="stus" ofType="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
</collection>
</resultMap>
<select id="selectByCollection" resultMap="clazzResultMap">
select c.cid,c.cname,s.sid,s.sname from t_clazz c left join t_stu s on c.cid = s.cid where c.cid = #{cid}
</select>
<!--这是多对一分步查询第二步:根据cid获取班级信息。 108-->
<select id="selectByIdStep2" resultType="Clazz">
select cid,cname from t_clazz where cid = #{cid}
</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="com.powernode.mybatis.mapper.StudentMapper">
<!--这是一对多 分步查询第二步:根据班级编号查询学生信息。。 108-->
<select id="selectByCidStep2" resultType="Student">
select * from t_stu where cid = #{cid}
</select>
<!--
分步查询的优点:
第一:复用性增强。可以重复利用。(大步拆成N多个小碎步。每一个小碎步更加可以重复利用。)
第二:采用这种分步查询,可以充分利用他们的延迟加载/懒加载机制。
什么是延迟加载(懒加载),有什么用?
延迟加载的核心原理是:用的时候再执行查询语句。不用的时候不查询。
作用:提高性能。尽可能的不查,或者说尽可能的少查。来提高效率。
在mybatis当中怎么开启延迟加载呢?
association标签中添加fetchType="lazy"
注意:默认情况下是没有开启延迟加载的。需要设置:fetchType="lazy"
这种在association标签中配置fetchType="lazy",是局部的设置,只对当前的association关联的sql语句起作用。
在实际的开发中,大部分都是需要使用延迟加载的,所以建议开启全部的延迟加载机制:
在mybatis核心配置文件中添加全局配置:lazyLoadingEnabled=true
实际开发中的模式:
把全局的延迟加载打开。
如果某一步不需要使用延迟加载,请设置:fetchType="eager"
-->
<!--两条SQL语句,完成多对一的分步查询。-->
<!--这里多对一是第一步:根据学生的id查询学生的所有信息。这些信息当中含有班级id(cid)-->
<!--这个association里面的select需要指定另外的第二步的sql语句的id-->
<resultMap id="studentResultMapByStep" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<association property="clazz"
select="com.powernode.mybatis.mapper.ClazzMapper.selectByIdStep2"
column="cid"
fetchType="eager"/>
</resultMap>
<select id="selectByIdStep1" resultMap="studentResultMapByStep">
select sid,sname,cid from t_stu where sid = #{sid}
</select>
<!--一条SQL语句,association。 107-->
<resultMap id="studentResultMapAssociation" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<!--
association:翻译为关联。一个Student对象关联一个Clazz对象
property:提供要映射的POJO类的属性名。
javaType:用来指定要映射的java类型。
-->
<association property="clazz" javaType="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
</association>
</resultMap>
<select id="selectByIdAssociation" resultMap="studentResultMapAssociation">
select
s.sid,s.sname,c.cid,c.cname
from
t_stu s left join t_clazz c on s.cid = c.cid
where
s.sid = #{sid}
</select>
<!--这个标签的作用就是指定学生表t_stu和Java pojo Student的对应关系 106
多对一映射的第一种方式:一条SQL语句,级联属性映射。-->
<resultMap id="studentResultMap" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<result property="clazz.cid" column="cid"/>
<result property="clazz.cname" column="cname"/>
</resultMap>
<select id="selectById" resultMap="studentResultMap">
select
s.sid,s.sname,c.cid,c.cname
from
t_stu s left join t_clazz c on s.cid = c.cid
where
s.sid = #{sid}
</select>
</mapper>
test中com.powernode.mybatis.test
ClazzMapperTest
package com.powernode.mybatis.test;
import com.powernode.mybatis.mapper.ClazzMapper;
import com.powernode.mybatis.pojo.Clazz;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class ClazzMapperTest {
//分步查询。第一步:根据班级编号获取班级信息。 112
@Test
public void testSelectByStep1(){
SqlSession sqlSession = SqlSessionUtil.openSession();
ClazzMapper mapper = sqlSession.getMapper(ClazzMapper.class);
Clazz clazz = mapper.selectByStep1(1000);
//System.out.println(clazz);
// 只访问班级名字。
System.out.println(clazz.getCname());
// 只有用到的时候才会去执行第二步SQL
//System.out.println(clazz.getStus());
sqlSession.close();
}
//根据班级编号查询班级信息。 111
@Test
public void testSelectByCollection(){
SqlSession sqlSession = SqlSessionUtil.openSession();
ClazzMapper mapper = sqlSession.getMapper(ClazzMapper.class);
Clazz clazz = mapper.selectByCollection(1000);
System.out.println(clazz);
sqlSession.close();
}
}
StudentMapperTest
package com.powernode.mybatis.test;
import com.powernode.mybatis.mapper.StudentMapper;
import com.powernode.mybatis.pojo.Student;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class StudentMapperTest {
//分部查询第一步:先根据学生的sid查询学生的信息。 108
//分步查询第二步:根据cid获取班级信息。 108
@Test
public void testSelectByIdStep1(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.selectByIdStep1(5);
//System.out.println(student);
// 懒加载 只需要看学生的名字 109
System.out.println(student.getSname());
// 程序执行到这里了,我想看看班级的名字 109
System.out.println(student.getClazz().getCname());
sqlSession.close();
}
//第二种方式 一条SQL语句,association 107
@Test
public void testSelectByIdAssociation(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.selectByIdAssociation(4);
System.out.println(student);
sqlSession.close();
}
//第⼀种⽅式:⼀条SQL语句,级联属性映射。
//根据id获取学生信息。同时获取学生关联的班级信息。 106
@Test
public void testselectById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.selectById(1);
System.out.println(student.getSid());
System.out.println(student.getSname());
System.out.println(student.getClazz().getCid());
System.out.println(student.getClazz().getCname());
System.out.println(student);
sqlSession.close();
}
}
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="jdbc.properties"/>
<settings>
<!--延迟加载的全局开关。默认值false不开启。 109-->
<!--什么意思:所有只要但凡带有分步的,都采用延迟加载。-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
<typeAliases>
<package name="com.powernode.mybatis.pojo"/>
</typeAliases>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.powernode.mybatis.mapper"/>
</mappers>
</configuration>
剩余的
pojo
utils
logback.xml
jdbc.properties
pom.xml
不做赘述