Mybatis的框架学习总结二

Mybatis的缓存机制

作用:缓存用于提高查询的效率,MyBatis 的缓存是使用 SQL 标签(也就是属性)的 ID 作为缓存的唯一标识的。执行相同的标签可以使用缓存,不同的标签不能使用缓存。

MyBatis 中有两种缓存机制。一级缓冲和二级缓存。

  • 一级缓冲默认开启。线程级别的缓存,SqlSession 的缓存, 在一个 SqlSession 生命周期中有效。SqlSession 关闭,缓存清空。

     public void find(){
            User u = new User();
            u.setUname("赵飞燕");
            User user = mapper.selBy(u);
            System.out.println(user);
            System.out.println("------缓存中的数据-------");
    		//session.clearCache();//清除SqlSession中的缓存
            //默认情况下缓存中有相同的数据,就从缓存中取数据
            User u2 = new User();
            u2.setUname("赵飞燕");
            User user2 = mapper.selBy(u2);
            System.out.println(user2);
        }
    
    
  • 二级缓冲, 进程级别的缓存,SqlSessionFactory 的缓存。在一个 SqlSessionFactory 生命周期中有效,可以在多个 SqlSession 生命中期中共享。默认关闭, 需要使用的时候, 要为某个命名空间开启二级缓存(在 mapper.xml 中配置)。在applicationContext-dao.xml核心配置文件中加。在mapper.xml映射文件中第一行加

<!--告知 MyBatis 框架开启二级缓存,在核心文件中添加-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>

//还需要在 Mapper 对应的xml中添加 cache 标签,表示对哪个mapper 开启缓存。

public void find(){
    User u = new User();
    u.setUname("赵飞燕");
    User user = mapper.selBy(u);
    System.out.println(user);
    System.out.println("------缓存中的数据-------");
  //二级缓存开启之后,会把一级缓存的数据移到SqlSessionFactory中
    User u2 = new User();
    u2.setUname("赵飞燕");
    User user2 = mapper.selBy(u2);
    System.out.println(user2);
}

想完整了解的Mybatis底层缓存机制的,可以看看这位大佬的博客

如何解决数据库中的列名与Pojo类中属性不一致

在查询语句中使用resultType属性,意味着使用Mybatis的Auto-Mapping(自动映射机制),即相同的列名和属性名会自动匹配。因此,当数据库表的列名和类的属性名不一致时,会导致查不到数据。解决该问题可以有两种方式:

  1. 方法一:查询时,可以通过列别名的方式将列名和属性名保持一致,继续使用自动映射, 从而解决该问题。但是较为麻烦。
  2. 方法二:使用用于自定义映射关系,可以由程序员自主制定列名和属性名的映射关系。一旦使用 resultMap, 表示不再采用自动映射机制。
<resultMap id="map" type="com.batis.pojo.Tuser">
    <id column="sid" property="tid"></id>   <!--主键用id标签,用result也可以,只是为了区别主键-->
    <!--column写数据库中的列名,property写pojo中对应的属性名-->
    <result column="uname" property="tname"></result>
    <result column="pwd" property="tpwd"></result>
    <result column="spower" property="tpower"></result>
</resultMap>
<select id="find" resultType="map">
    select sid,uname,pwd,spower from t_user2
</select>

多表连接查询

业务装配实现多表查询(多对一)

mapper 层只做单表查询操作, 在 service 层进行手动装配,实现关联查询的结果。

实例:

oracle数据库:

create table student(
       sid number(3) primary key,
       sname varchar2(20),
       age number(3),
       cid number(3),
       constraints fk_student_cid foreign key(cid) references clazz(cid)
)
create table clazz(
       cid number(3) primary key,
       cname varchar2(20),
       roon varchar2(20)
)

创建实体类:创建班级类(Clazz)和学生类(Student),并在 Student 中添加一个 Clazz 类型的属性,用于表示学生的班级信息。

mapper层,提供 StudentMapper 和 ClazzMapper, StudentMapper 查询所有学生信息, ClazzMapper 根据编号查询班级信息。调用 mapper 层,先查询所有学生,再根据每个学生的班级编号查询班级信息, 手动进行组装,称之为业务装配。

resultMap的N+1方式实现多表查询(多对一)

这种方法是在配置文件中直接完成装配,实体类没有变动。

mapper层,提供 StudentMapper 和 ClazzMapper, StudentMapper 查询所有学生信息 , ClazzMapper 根据编号查询班级信息 ,再 StudentMapper 中使用设置装配。

  1. 用于关联一个对象
    • property: 指定要关联的属性名。
    • select: 设定要继续引用的查询, namespace+id。
    • column: 查询时需要传递的列。
<resultMap id="m" type="Student">
    <!--同名列的id和result可以省略不写-->
    <id property="sid" column="sid"></id>
    <result property="" column=""></result>  <!--如果pojo实体类中的属性名和数据库中的列名不一致,那么要写result标签中的映射关系-->
    <!--property:写在student实体类中持有Clazz的属性名
    select:通过哪条sql完成班级的查询,
    column:根据指定查询的列名
    javaType:查询之后的结果需要封装成的对象
    -->
    <association property="clazz" select="com.batis.mapper.ClazzMapper.selByCno" javaType="Clazz" column="cid">
        <!--同名列的id和result可以省略不写-->
        <id></id>
        <result></result>
    </association>
</resultMap>
<select id="selByName2" resultMap="m">
    select * from student where sname = #{0}
</select>

由于装配已经完成,service 层只需要调用 mapper 即可,不需要再进行装配了。

resultMap 的关联方式实现多表查询(多对一)

  1. 在 StudentMapper.xml 中定义多表连接查询 SQL 语句。一次性查到需要的所有数据,包括对应班级的信息。

  2. 通过定义映射关系,并通过指定对象属性的映射关系。可以把看成一个使用。javaType 属性表示当前对象, 可以写全限定路径或别名。

<resultMap id="m" type="Student">
    <!--主键得写上,同名列的result可以省略不写-->
    <id property="sid" column="sid"></id>
    <result property="" column=""></result>  <!--如果pojo实体类中的属性名和数据库中的列名不一致,那么要写result标签中的映射关系-->
    <!--property:写在student实体类中持有Clazz的属性名
    select:通过哪条sql完成班级的查询,
    column:根据指定查询的列名
    javaType:查询之后的结果需要封装成的对象
    -->
    <result property="cid" column="cid"></result>  <!--外键的列映射关系一定得写上,否则cid没有值-->
    <association property="clazz" select="com.batis.mapper.ClazzMapper.selByCno" javaType="Clazz" column="cid">
        <id></id>
        <result></result>
    </association>
</resultMap>
<select id="selByName2" resultMap="m">
    select * from student where sname = #{0}
</select>

resultMap 的 N+1 方式实现多表查询(一对多)

mapper层提供 ClazzMapper 和 StudentMapper, ClazzMapper 查询所有班级信息,StudentMapper 根据班级编号查询学生信息 。在 ClazzMapper 中使用设置装配。

  1. 用于关联一个集合
  • property: 指定要关联的属性名

  • select: 设定要继续引用的查询, namespace+id

  • column: 查询时需要传递的列

<!--<collection property="" select="" column=""></collection>-->
<resultMap id="cc" type="Clazz">
    <id property="cid" column="cid"></id>   <!--作为主键又是外键的列一定得写上,否则clazz中的cid没有值-->
    <collection property="stus" select="com.batis.mapper.StudentMapper.selByCid" column="cid"></collection>
</resultMap>
<select id="selByCno" resultMap="cc">
    select * from clazz where cid = #{0}
</select>

resultMap 的关联方式实现多表查询(一对多)

  1. 在 ClazzMapper.xml 中定义多表连接查询 SQL 语句,一次性查到需要的所有数据, 包括对应学生的信息。

  2. 通过定义映射关系,并通过指定集合属性泛型的映射关系。可以把看成一个使用。ofType 属性表示集合的泛型,可以写全限定路径或别名。<collection property="" javaType="" ofType="" >

<resultMap id="dd" type="Clazz">
    <!--数据库列名与pojo实体类是映射关系一定要写上-->
    <id property="cid" column="cid"></id>
    <result property="cname" column="cname"></result>
    <result property="roon" column="roon"></result>
    <!--
    javaType:返回的对象类型,查MyBatis的中文文档集合List对象的别名是list
    ofType:返回集合的泛型
    -->
    <collection property="stus" javaType="list" ofType="Student">
        <!--数据库列名与pojo实体类是映射关系一定要写上-->
        <id property="sid" column="sid"></id>
        <result property="sname" column="sname"></result>
        <result property="age" column="age"></result>
    </collection>
</resultMap>
<select id="selByCno2" resultMap="dd">
    select c.cid,c.cname,c.roon,s.sid,s.sname,s.age from clazz c join student s on c.cid = s.cid where c.cid = #{0}
</select>

通过 Auto-Mapping 实现多表查询

a) 通过 MyBatis 的 Auto-Mapping 机制及数据库查询时的别名结合,可以方便的实现多表查询。

b) SQL 语句中, 别名出现特殊符号时,必须进行处理. MySQL可以使用(``)符号,Oracle 可以使用("")符号。缺点:适合于一对多的查询,多对一查集合不好用。

<!--查询:员工的信息及其部门信息(一对多)-->
<?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.batis.mapper.StudentMapper">
    <select id="selAuto" resultType="Student">
        <!--clazz是Student的实体类中持有Clazz类的实姓名-->
        select s.sid,s.sname,s.age,s.cid,c.cid "clazz.cid",c.cname "clazz.cname",c.roon "clazz.roon" from student s join clazz c on s.cid = c.cid where s.sname=#{0}
    </select>
</mapper>

用注解完成增删改查

在接口的抽象方法上写@select(“sql语句”),@insert(“sql语句”),@delete(“sql语句”),@update(“sql语句”)以替代mapper.xml文件。

import com.batis.pojo.Student;
import com.batis.pojo.User;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;


public interface StudentMapper {
    @Select(value = "select * from Student where sname=#{0}")  //用注解替代了StudentMapper.xml配置文件
    public Student selByName(String sname);

    @Update(value = "update Student set sname=#{sname},age=#{age} where sid = #{sid} ")
    public int updateStu(Student stu);
}
posted @ 2021-03-29 15:34  念笙  阅读(103)  评论(0)    收藏  举报