mybatis一对多,多对一经典案例及优缺点分析

准备数据

新建俩张表(student表,clalss表)sql语句如下:

create table student(
sId int primary key auto_increment,
sName varchar(20) not null,
cId int not null,
constraint f_sid_cid foreign key(cId) references class(cId)
)engine = innodb,charset=utf8;

create table class(
cId int primary key auto_increment,
cName varchar(20) not null
)engine = innodb,charset=utf8;

填充数据sql语句如下:

insert into class (cName) values('A1871');
insert into class (cName) values('A1872');
insert into class (cName) values('A1873');
insert into class (cName) values('A1874');
insert into class (cName) values('A1875');

insert into student (sName,cId) values('李四',1);
insert into student (sName,cId) values('王五',1);
insert into student (sName,cId) values('可乐',1);
insert into student (sName,cId) values('雪碧',2);
insert into student (sName,cId) values('西红柿',2);

class类

public class Classz implements Serializable {
    
    
    private static final long serialVersionUID=1L;
    private Integer cId;
    private String cName;
    private List<Student> students;
    此处省略get set tostring方法.......

student类

public class Student implements Serializable {
    
    
    private static final long serialVersionUID=1L;
    private Integer sId;
    private String sName;
    private Classz classz;
    此处省略get set tostring方法.......

ClassMapper

@Repository
public interface ClassMapper {
    
    
    Classz selectClassByCid(@Param("cId") int id);    
    Classz selectClassByCidLazy(@Param("cId") int id);
}

studentMapper

@Repository
public interface StudentMapper {
    
    
    //对应的xml的resultType为Student即可,属性会自动填充
    List<Student> selectStudentsByCid(@Param("cId") int id);
    Student selectStudentBySid(@Param("sId") int id);
}

一对多

就是查某个班级信息的同时查询下面的所有学生也就是对应着ClassMapper下的selectClassByCid方法。

方法一:直接写sql语句进行多表联查进行结果集的映射

ClassMapper.xml

1. type: 返回值的类型
2. id标签:用于主键的映射
3. property:实体类中的属性名
4. collection:表明返回的结果集是集合,用于多对多映射,多指的是属性property=“students” 是list类型是要进行一一映射结果集的,对多的多指的是有多条数据映射
5. oftype:集合中的类型
6. column:查询过程中映射的字段名称
7. result:用于属性的映射
8. javaType: 确定这个属性类型

<mapper namespace="com.zzh.data.mapper.ClassMapper">
    <resultMap id="Classz" type="com.zzh.data.entity.Classz">
        <id property="cId" column="ccId"></id>
        <result property="cName" column="cName"></result>
        <collection property="students" 
        ofType="com.zzh.data.entity.Student"
        javaType="ArrayList">
            <id property="sId" column="sId"></id>
            <result property="sName" column="sName"></result>
        </collection>
    </resultMap>
    <select id="selectClassByCid" resultMap="Classz">
         select c.cName,c.cId as ccId,s.sName,s.sId,s.Cid as scId from class as c
  left join student as s on c.cId = s.Cid
  where c.cId = #{cId};
    </select>
</mapper>
优点 缺点
简单明了的就可以完成对应的需求,结果映射就完事了 对于书写sql语句的水平有一定的要求,其次是如果只是需要拿到班级的名字,而不要拿到对应班级下面的所有学生,那么这种写法一次性的会把所有的数据都查出来并且封装到class类中,这无疑是非常消耗性能的

方法二:逐个开启属性的按需加载功能(懒加载)

ClassMapper.xml

1. fetchType=eager表示selectClassByCidLazy的时候立即执行关联的selectStudentsByCid中的sql语句
2. fetchType=lazy只有用到students这个属性时,才会执行关联的select中的selectStudentsByCid中的sql语句

<select id="selectClassByCidLazy" resultMap="ClasszLazy">
         select * from class where cId = #{cId};
    </select>
    <!--如果开启了全局的lazy开关,那么不必在一个个的加fetchType="lazy"的属性了-->
    <resultMap id="ClasszLazy" type="com.zzh.data.entity.Classz">
        <id property="cId" column="cId"></id>
        <result property="cName" column="cName"></result>
        <collection property="students"
                    ofType="com.zzh.data.entity.Student"
                    javaType="ArrayList"
                    fetchType="lazy"
                    select="com.zzh.data.mapper.StudentMapper.selectStudentsByCid"
                    column="cId"></collection>
    </resultMap>

studentMapper.xml

返回类型是List,resultType也只需要写list中的类型。多条数据mybatis会自动帮我们进行封装成list

<mapper namespace="com.zzh.data.mapper.StudentMapper">
    <select id="selectStudentsByCid" parameterType="int" resultType="com.zzh.data.entity.Student">
    select * from student where cId = #{cId}
    </select>
</mapper>
优点 缺点
可以实现对属性的按需加载,大大提高的整体项目的性能 配置起来可能比较复杂

方法三:开启全部的属性按需加载(懒加载全局配置)
此时去掉那些fetchType = lazy属性照样懒加载

mybatis:
  mapper-locations: classpath:mapperXml/*.xml
  configuration:
    #开启全局的懒加载 aggressive-lazy-loading: false lazy-loading-enabled: true
    #true 会使带有延时属性的对象立即加载
    #false 每种属性按需加载
    #aggressive-lazy-loading默认为true
    aggressive-lazy-loading: false
    #lazy-loading-enabled默认为false 属性延时加载的开关
    lazy-loading-enabled: true
    #开启mysqlbatis打印sql
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

一对多测试方法一:正常获取数据

在这里插入图片描述

一对多测试方法二:按需获取数据

只有在用到students时才会去DB
在这里插入图片描述

一对多测试方法三:按需获取数据

效果和上面的测试方法二一样,读者可以自行去测试

多对一

也就是查询学生的信息的同时去查询对应的所在的班级信息

StudentMapper.xml

  • association:用于一对一映射,一指的是属性property=“classz” 是单个的只需要单个映射结果集,对一的一指的是只有一条数据映射
<mapper namespace="com.zzh.data.mapper.StudentMapper">
    <select id="selectStudentBySid" parameterType="int" resultMap="student">
    select * from student where sId = #{sId}
    </select>
    <resultMap id="student" type="com.zzh.data.entity.Student">
        <id property="sId" column="sId"></id>
        <result property="sName" column="sName"></result>
        <association property="classz" column="cId"
                     javaType="com.zzh.data.entity.Classz">
        </association>
    </resultMap>
</mapper>

多对一测试成功

成功查出了该学生及其所在的班级信息
在这里插入图片描述
本文所用测试代码下载链接

猜你喜欢

转载自blog.csdn.net/qq_42875345/article/details/109690844