面试宝典-【Mybatis】

目录

1.什么是mybatis?

2.ORM是什么?

3.mybatis优缺点?

4.Hibernate 和 MyBatis 有什么区别?

5. MyBatis 使用过程?

6.如何保证mapper接口和映射文件一致?

7.MyBatis 生命周期?

8. ${}和#{}的区别?

9.在 mapper 中如何传递参数?

10.实体类属性名和表中字段名不一样 ,怎么办? 

11.模糊查询 like 语句该怎么写? 

12.Mybatis 能执行一对一、一对多的关联查询吗? 

13.Mybatis如何实现分步查询?

14.Mybatis 是否支持延迟加载?原理?

15. 如何获取生成的主键?

16.MyBatis 支持动态 SQL 吗?

17.说说 Mybatis 的一级、二级缓存?

18.Mybatis缓存查询顺序?

19.能说说 MyBatis 的工作原理吗?

20.MyBatis 的功能架构是什么样的?

21.Mybatis 都有哪些 Executor 执行器?

22.Mybatis 中如何指定使用哪一种 Executor 执行器?

23.为什么 Mapper 接口不需要实现类? 

24.MyBatis 是如何进行分页的? 


1.什么是mybatis?

  • MyBatis 是支持定制化SQL、存储过程以及高级映射的优秀半自动的ORM持久层框架
  • MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。
  • Mybatis就是帮助程序员将数据存取到数据库里面。

2.ORM是什么?

  • ORM(Object Relational Mapping):对象关系映射,将java中的实体类对象和关系型数据库中的数据创建映射关系。
    • 类    ----------表
    • 属性 ---------字段/列
    • 对象 ---------记录/行

3.mybatis优缺点?

优点:

  • 与JDBC相比,减少了50%以上的代码量。
  • MyBatis是易学的持久层框架,小巧并且简单易学。
  • MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML文件里,从程序代码中彻底分离,降低耦合度,便于统一的管理和优化,并可重用。
  • 提供XML标签,支持编写动态的SQL,满足不同的业务需求。
  • 提供映射标签,支持对象与数据库的ORM字段关系映射

缺点:

  • SQL语句的编写工作量较大,对开发人员编写SQL的能力有一定的要求。
  • SQL语句依赖于数据库,导致数据库不具有好的移植性,不可以随便更换数据库。

4.Hibernate 和 MyBatis 有什么区别?

相同点:

  • 都是对 jdbc 的封装,都是应用于持久层的框架。

不同点:

  • 映射关系    
    • MyBatis 是一个半自动映射的框架,配置 Java 对象与 sql 语句执行结果的对应关系,多表关联关系配置简单
    • Hibernate 是一个全表映射的框架,配置 Java 对象与数据库表的对应关系,多表关联关系配置复杂
  • SQL 优化和移植性
    • Hibernate 对 SQL 语句封装,代码开发量少,但 SQL 语句优化困难。
    • MyBatis 需要手动编写 SQL,开发工作量相对大些。直接使用 SQL 语句操作数据库,不支持数据库无关性,但 sql 语句优化容易。
  • MyBatis 和 Hibernate 的适用场景不同
    • Hibernate 是标准的 ORM 框架,SQL 编写量较少,但不够灵活,适合于需求相对稳定,中小型的软件项目,比如:办公自动化系统
    • MyBatis 是半 ORM 框架,需要编写较多 SQL,但是比较灵活,适合于需求变化频繁,快速迭代的项目,比如:电商网站

5. MyBatis 使用过程?

  • 1.创建配置文件:创建一个 MyBatis 的配置文件(通常是 mybatis-config.xml)这个文件包含了 MyBatis 的全局配置信息,如数据源、事务管理器、别名等。
  • 2.创建mapper接口:创建操作数据库的方法(增、删、改、查)
  • 3.创建映射文件:为每一个表创建一个或多个 SQL 映射文件,文件包含了 SQL 语句、参数映射、结果映射等信息。
  • 4.加载核心配置文件:通过Resource获取核心配置文件的字节流
  • 4.创建 SqlSessionFactory:通过SqlSessionFactoryBuilder加载字节流进行创建
  • 5.创建 SqlSession:通过 SqlSessionFactory.opensession()创建java和mysql之间的会话
  • 6.通过 sqlsession 执行数据库操作:先获取getMapper,然后再执行 SQL 语句(代理)
  • 7.调用 session.commit()提交事务:如果是更新、删除语句,我们还需要提交一下事务。
  • 8.调用 session.close()关闭会话:最后一定要记得关闭会话。

6.如何保证mapper接口和映射文件一致?

  • 1.映射文件的namespace要和mapper接口的全类路径名保持一致
  • 2.映射文件中的sql语句的id要和mapper接口中的方法名保持一致

7.MyBatis 生命周期?

一般说的 MyBatis 生命周期就是这些组件的生命周期。

  • SqlSessionFactoryBuilder:一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的生命周期只存在于方法的内部。
  • SqlSessionFactory:SqlSessionFactory 是用来创建 SqlSession 的,相当于一个数据库连接池,每次创建 SqlSessionFactory 都会使用数据库资源,多次创建和销毁是对资源的浪费。所以 SqlSessionFactory 是应用级的生命周期,而且应该是单例的。
  • SqlSession:SqlSession 相当于 JDBC 中的 Connection,SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的生命周期是一次请求或一个方法。
  • Mapper:映射器是一些绑定映射语句的接口。映射器接口的实例是从 SqlSession 中获得的,它的生命周期在 sqlsession 事务方法之内,一般会控制在方法级。

8. ${}和#{}的区别?

MyBatis获取参数值的两种方式:${}#{}#{} 是预编译处理,${} 是字符串替换。

  • #{}
    • 当使用 #{} 时,MyBatis 会在 SQL 执行之前,将占位符替换为问号 ?,并使用参数值来替代这些问号。
    • 由于 #{} 使用了预处理,它能有效防止 SQL 注入,可以确保参数值在到达数据库之前被正确地处理和转义。
  • ${}:
    • 当使用 ${} 时,参数的值会直接替换到 SQL 语句中去,而不会经过预处理。
    • 存在 SQL 注入的风险,因为参数值会直接拼接到 SQL 语句中,假如参数值是 1 or 1=1,那么 SQL 语句就会变成 SELECT * FROM users WHERE id = 1 or 1=1,这样就会导致查询所有用户的结果。

9.在 mapper 中如何传递参数?

  • 1.mapper接口的参数为单个字面量类型:可以通过${}或#{}以任意的名称获取参数值
  • 2.mapper接口的参数为多个: 此时Mybatis会将这些参数放在一个map集合中,以两种方式进行存储
    • 以arg0,arg1..为键,以参数为值
    • 以param1,param2为键,以参数为值
  • 3.mapper接口是一个实体类类型的参数:只需要通过#{}或${}以属性的方式访问属性值即可
  • 4.使用@Parma命名参数:此时Mybatis会将这些参数放在一个map集合中,以两种方式进行存储,只需要通过#{}或${}以键的方式访问即可
    • .以@Parma注解的值为键,以参数为值
    • .以param1,param2为键,以参数为值

总结:大体分为两种,实体类类型和以@Parma注解命名

10.实体类属性名和表中字段名不一样 ,怎么办? 

  • 1.在查询的 SQL 语句中为字段定义别名,让字段名的别名和实体类的属性名一致
<select id="getOrder" parameterType="int" resultType="com.jourwon.pojo.Order">
       select order_id id, order_no orderno ,order_price price form orders where order_id=#{id};
</select>
  • 2.通过 resultMap 中的<result>来映射字段名和实体类属性名的一一对应的关系。
<select id="getOrder" parameterType="int" resultMap="orderResultMap">
  select * from orders where order_id=#{id}
</select>

<resultMap type="com.jourwon.pojo.Order" id="orderResultMap">
    <!–用id属性来映射主键字段–>
    <id property="id" column="order_id">
    <!–用result属性来映射非主键字段,property为实体类属性名,column为数据库表中的属性–>
  <result property ="orderno" column ="order_no"/>
  <result property="price" column="order_price" />
</resultMap>
  • 3. 设置全局配置,将下划线自动映射为驼峰
springboot中:
#下划线转驼峰
mybatis.configuration.map-underscore-to-camel-case=true

mybatis XML配置中
<configuration>
    <!-- 全局配置 -->
    <settings>
       <!-- 是否开启自动驼峰命名规则(camel case)映射,即从数据库列名 A_COLUMN 到属性名 aColumn 的类似映射 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
</configuration>

11.模糊查询 like 语句该怎么写? 

  • 1.'%${question}%'
select * from t_user where username like '%${username}%'
  • 2.CONCAT('%',#{question},'%')
select * from t_user where username like concat('%',#fusername},'%')
  • 3."%"#{question}"%"
select * from t_user where username like "%"#fusername}"%"

12.Mybatis 能执行一对一、一对多的关联查询吗? 

不止支持一对一、一对多的关联查询,还支持多对多、多对一的关联查询。

  • 一对一<association>

订单和支付是一对一的关系,这种关联的实现:

实体类:

public class Order {
    private Integer orderId;
    private String orderDesc;

    /**
     * 支付对象
     */
    private Pay pay;
    //……
}

结果映射:

<!-- 订单resultMap -->
<resultMap id="peopleResultMap" type="cn.fighter3.entity.Order">
    <id property="orderId" column="order_id" />
    <result property="orderDesc" column="order_desc"/>
    <!--一对一结果映射-->
    <association property="pay" javaType="cn.fighter3.entity.Pay">
        <id column="payId" property="pay_id"/>
        <result column="account" property="account"/>
    </association>
</resultMap>

sql语句:

<select id="getTeacher" resultMap="getTeacherMap" parameterType="int">
    select * from order o
     left join pay p on o.order_id=p.order_id
    where  o.order_id=#{orderId}
</select>
  • 一对多<collection>

口商品分类和商品,是一对多的关系。

实体类:

public class Category {
    private int categoryId;
    private String categoryName;

    /**
    * 商品列表
    **/
    List<Product> products;
    //……
}

结果映射:

<resultMap type="Category" id="categoryBean">
    <id column="categoryId" property="category_id" />
    <result column="categoryName" property="category_name" />

    <!-- 一对多的关系 -->
    <!-- property: 指的是集合属性的值, ofType:指的是集合中元素的类型 -->
    <collection property="products" ofType="Product">
        <id column="product_id" property="productId" />
        <result column="productName" property="productName" />
        <result column="price" property="price" />
    </collection>
</resultMap>

sql语句:

<!-- 关联查询分类和产品表 -->
<select id="listCategory" resultMap="categoryBean">
    select c.*, p.* from category_ c left join product_ p on c.id = p.cid
</select>
  • <association>:一对一,多对一
  • <collection>>:一对多,多对多

13.Mybatis如何实现分步查询?

使用association进行分步查询~

                先查员工,再根据员工id查部门,将查到的部门信息赋值给员工

  • 第一步:先查员工

mapper接口:

    /**
     * 分布查询员工以及员工所对应的部门
     * 第一步:查询员工信息
     */
    Emp getEmpAndDeptByStepOne(@Param("empId")Integer empId);

映射文件:

    <resultMap id="empAndDeptByStepResultMap" type="emp">
        <id property="empId" column="emp_id"></id>
        <result property="empName" column="emp_name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <result property="email" column="email"></result>
        <association property="dept"
                     select="com.xz.mapper.DeptMapper.getEmpAndDeptByStepTwo"
                     column="did"></association>
    </resultMap>
    <!-- Emp getEmpAndDeptByStepOne(@Param("empId")Integer empId);-->
    <select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
        select * from t_emp where emp_id=#{empId}
    </select>
  • 第二部:在查部门

mapper接口:

    /**
     * 分布查询员工以及员工所对应的部门
     * 第二步:通过did查询员工所对应的部门
     */
    Dept getEmpAndDeptByStepTwo(@Param("deptId")Integer deptId);

映射文件:

   <select id="getEmpAndDeptByStepTwo" resultType="dept">
        select * from t_dept where dept_id=#{deptId}
    </select>

关于association的属性含义:

  • property:多对应的属性
  • select:分布查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
  • colum:设置分布查询的条件 
  • fetchType="lazy(延迟加载)|eager(立即加载)"
    • fetchType:当开启全局的延迟加载之后,可通过此属性手动控制延迟加载的效果

分布查询的优点:

  • 可以实现延迟加载必须在核心配置文件中设置全局配置信息

14.Mybatis 是否支持延迟加载?原理?

MyBatis的延迟加载(也称为懒加载或按需加载)原理主要基于Java的动态代理和MyBatis的映射配置文件。

  • 支持!
    • Mybatis 支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询。在 Mybatis 配置文件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false
      • lazyLoadingEnabled:延迟加载的全局开关。所有关联对象都会延迟加载(默认:false)

      • aggressiveLazyLoading:任何方法的调用都会加载该对象的所有属性(默认:false)

      • 可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载, fetchType="lazy(延迟加载)|eager(立即加载)"

  • 原理

    • 使用 CGLIB 动态代理创建目标对象的代理对象,当调用目标方法时,进入拦截器方法。比如调用 a.getB().getName(),拦截器 invoke()方法发现 a.getB()是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 a.getB().getName()方法的调用。这就是延迟加载的基本原理。

15. 如何获取生成的主键?

  •  userGenerateKeys:设置当前标签中的sql使用了自增的id
  •  KeyProperty:将自增的主键的值赋值给传输到映射文件中参数的某个属性

<insert id="insert" useGeneratedKeys="true" keyProperty="userId" >
    insert into user(
    user_name, user_password, create_time)
    values(#{userName}, #{userPassword} , #{createTime, jdbcType= TIMESTAMP})
</insert>

应用场景:多对多,将俩表关联的信息,整合到第三张表时,为其设置自增id

16.MyBatis 支持动态 SQL 吗?

Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。

  • 1.if
    • 根据标签中的test属性所对应的表达式决定标签中的内容是否需要拼接到sql中
    •  小技巧:where 后添加 1=1 恒成立条件!!!
    <select id="getEmpByCondition" resultType="emp">
       select * from t_emp where 1=1
        <if test="empName!=null and empName!=''">
            and emp_name=#{empName}
        </if>
        <if test="age!=null and age!=''">
            and age=#{age}
        </if>
        <if test="sex!=null and sex!=''">
            and sex=#{sex}
        </if>
        <if test="email!=null and email!=''">
            and email=#{email}
        </if>
    </select>
  • 2.where
    • 当where标签中有内容时,会自动生成where关键字,并且将内容前多余的and 或or去掉
    • 当where标签中没有内容时,此时where标签没有任何效果
    • 注意:where标签不能将其中内容后的and或or去掉
        <where>
            <if test="empName!=null and empName!=''">
                and emp_name=#{empName}
            </if>
            <if test="age!=null and age!=''">
                and age=#{age}
            </if>
            <if test="sex!=null and sex!=''">
                and sex=#{sex}
            </if>
            <if test="email!=null and email!=''">
                and email=#{email}
            </if>
        </where> 
  • 3.trim
    • 若标签中有内容时:

      • prefix,suffix:将trim标签中内容前面或后面添加指定内容
      • suffixOverrides,prefixOverrides:将trim标签中内容前面或后面删除指定内容
    • 若标签中无内容时,trim标签没有任何效果!!!

   <select id="getEmpByCondition" resultType="emp">
        select * from t_emp
        <trim prefix="where" suffixOverrides="and|or">
            <if test="empName!=null and empName!=''">
                emp_name=#{empName} and
            </if>
            <if test="age!=null and age!=''">
                age=#{age} and
            </if>
            <if test="sex!=null and sex!=''">
                sex=#{sex} or
            </if>
            <if test="email!=null and email!=''">
                email=#{email}
            </if>
        </trim>
    </select>
  • 4.choose,when,otherwise
    • 相当于java中的if....else  if.....else,只要有一个条件满足就不再执行后面的,否则执行otherwise中的条件
      • when至少有一个,otherwise至多有一个
  <select id="getEmpByChoose" resultType="emp">
        select * from t_emp
        <where>
            <choose>
                <when test="empName!=null and empName!=''">
                    emp_name=#{empName}
                </when>
                <when test="age!=null and age!=''">
                    age=#{age}
                </when>
                <when test="sex!=null and sex!=''">
                    sex=#{sex}
                </when>
                <when test="email!=null and email!=''">
                    email=#{email}
                </when>
                <otherwise>
                    did=1
                </otherwise>
            </choose>
        </where>
    </select>
  • 5.foreach
    • collection:设置需要循环的数组或集合
    • item:表示数组或集合中的每一个数据
    • separator:循环体之间的分隔符
    • open:foreach标签所循环的所有内容的开始符
    • close:foreach标签所循环的所有内容的结束符
#根据id批量删除

方式一:使用 , 分割 
 <delete id="deleteMoreByArray">
        delete from t_emp where emp_id in
        <foreach collection="empIds" item="empId" separator="," open="(" close=")">
            #{empId}
        </foreach>
    </delete>

方式一:使用 or 分割 
   <delete id="deleteMoreByArray">
        delete from t_emp where
        <foreach collection="empIds" item="empId" separator="or">
            emp_id=#{empId}
        </foreach>
    </delete>


#批量添加
   <!--int insertMoreByList(List<Emp> emps);-->
    <insert id="insertMoreByList">
        insert into t_emp values
        <foreach collection="emps" item="emp" separator=",">
            (null,#{emp.empName},#{emp.age},#{emp.sex},#{emp.email},null)
        </foreach>
    </insert>
  • 6.sql
    • <sql_ id="empColumns">emp_id,emp_name, age,sex,email</sql>:设置sql片段
    • <include refid="empColumns">:引用sql片段
  <sql id="empColumns">emp_id,emp_name,age,sex,email</sql>
 
    <!-- List<Emp> getEmpByCondition(Emp emp);-->
    <select id="getEmpByCondition" resultType="emp">
        select <include refid="empColumns"></include>from t_emp
        <trim prefix="where" suffixOverrides="and|or">
            <if test="empName!=null and empName!=''">
                emp_name=#{empName} and
            </if>
            <if test="age!=null and age!=''">
                age=#{age} and
            </if>
            <if test="sex!=null and sex!=''">
                sex=#{sex} or
            </if>
            <if test="email!=null and email!=''">
                email=#{email}
            </if>
        </trim>
    </select>
  • 7.set
    •  可以用在动态更新的时候
<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

17.说说 Mybatis 的一级、二级缓存?

  • 一级缓存:
    • 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 SqlSession,各个 SqlSession 之间的缓存相互隔离,
    •  一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取不会从数据库重新访问
      • 使一级缓存失效的四种情况

        • 不同的SqlSession对应不同的一级缓存
        • 同一个SqlSession但是查询条件不同 
        • 同一个SqlSession两次查询期间执行了任何一次增删改操作
        • 同一个SqlSession两次查询期间手动清空了缓存-sqlSession.clearCache()
      • 一级缓存默认开启!!!

  • 二级缓存:

    • 默认也是采用 PerpetualCache,HashMap 存储,默认也是采用 PerpetualCache,HashMap 存储

    •  二级缓存是SqlSessionFactory级别 ,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取

      • 二级缓存开启的条件

        • 在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
        • 在映射文件中设置标签<cache />
        • 二级缓存必须在SqlSession关闭或提交之后有效
        • 查询的数据所转换的实体类类型必须实现序列化的接口
      • 使二级缓存失效的情况:两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

18.Mybatis缓存查询顺序?

  1. 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据
  2. 如果二级缓存没有命中再查询一级缓存
  3. 如果一级缓存也没有命中则查询数据库
  4. SqlSession关闭之后,一级缓存中的数据会写入二级缓存

19.能说说 MyBatis 的工作原理吗?

1.整体分为两大步构建会话工厂、会话运行

  • 构建会话工厂:
    • 获取配置、
      • MyBatis 在初始化时,会读取配置文件(如 mybatis-config.xml),该配置文件包含了数据源信息(数据库连接的配置)、映射文件信息(即 SQL 语句和 Java 对象之间的映射关系)等,封装到configuration中;
    • 构建 SqlSessionFactory
      • SqlSessionFactory 只是一个接口,构建出来的实际上是它的实现类的实例,一般我们用的都是它的实现类 DefaultSqlSessionFactory,
      • SqlSessionFactory 是 MyBatis 的核心类,它负责创建 SqlSession。
  • 会话运行:
    • Executor(执行器):Executor 起到了至关重要的作用,SqlSession 只是一个门面,相当于客服,真正干活的是是 Executor,就像是默默无闻的工程师。它提供了相应的查询和更新方法,以及事务方法。
    • StatementHandler(数据库会话器):StatementHandler,顾名思义,处理数据库会话的。我们以 SimpleExecutor 为例,先生成了一个 StatementHandler 实例,再拿这个 handler 去执行 query。
    • ParameterHandler (参数处理器):PreparedStatementHandler 里对 sql 进行了预编译处理,里面还会用到 typeHandler 类型处理器,对类型进行处理。
    • ResultSetHandler(结果处理器):mybatis 为我们提供了一个 DefaultResultSetHandler,通常都是用这个实现类去进行结果的处理的。

2.整体总结

  • 1.读取 MyBatis 配置文件——mybatis-config.xml 、加载映射文件——映射文件即 SQL 映射文件,文件中配置了操作数据库的 SQL 语句。最后生成一个配置对象。
  • 2.构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。
  • 3.创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法。
  • 4.Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。
  • 5.StatementHandler:数据库会话器,串联起参数映射的处理和运行结果映射的处理。
  • 6.参数处理:对输入参数的类型进行处理,并预编译。
  • 7.结果处理:对返回结果的类型进行处理,根据对象映射规则,返回相应的对象。

20.MyBatis 的功能架构是什么样的?

  • API 接口层:提供给外部使用的接口 API,开发人员通过这些本地 API 来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
  • 数据处理层:负责具体的 SQL 查找、SQL 解析、SQL 执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
  • 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。

21.Mybatis 都有哪些 Executor 执行器?

一、mybatis的执行器有三种:SimpleExecutor、ReuseExecutor、BatchExecutor

  • 1. SimpleExecutor(简单执行器):是 MyBatis 中默认使用的执行器,每执行一次 update 或 select,就开启一个 Statement 对象,用完就直接关闭 Statement 对象(可以是 Statement 或者是 PreparedStatment 对象)
  • 2.ReuseExecutor(可重用执行器)执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map<String, Statement>内,供下一次使用。简言之,就是重复使用 Statement 对象。
  • 3.BatchExecutor(批处理执行器):这里的重用指的是重复使用 Statement,它会在内部使用一个 Map 把创建的 Statement 都缓存起来,每次执行 SQL 命令的时候,都会去判断是否存在基于该 SQL 的 Statement 对象,如果存在 Statement 对象并且对应的 connection 还没有关闭的情况下就继续使用之前的 Statement 对象,并将其缓存起来。每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理。

二、作用范围:Executor 的这些特点,都严格限制在 SqlSession 生命周期范围内。

22.Mybatis 中如何指定使用哪一种 Executor 执行器?

  • 在 Mybatis 配置文件中,在设置(settings)可以指定默认的 ExecutorType 执行器类型,也可以手动给 DefaultSqlSessionFactory 的创建 SqlSession 的方法传递 ExecutorType 类型参数,如SqlSession openSession(ExecutorType execType)
  • 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。

23.为什么 Mapper 接口不需要实现类? 

  • 动态代理实现

代理对象拦截到接口方法后,根据方法名称找到SQL 语句和映射关系,通过SqlSession执行SQL

24.MyBatis 是如何进行分页的? 

是MyBatis分页的几种常见方式及其原理:

  • 1.基于RowBounds的分页:
    • 分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义插件,拦截 Executor 的 query 方法。
    • 在执行查询的时候,拦截待执行的 sql,然后重写 sql,根据 dialect 方言,添加对应的物理分页语句和物理分页参数。
      • 举例:select * from student,拦截 sql 后重写为:select t.* from (select * from student) t limit 0, 10
  • 2.基于物理分页的插件(如PageHelper):
    • 使用PageHelper插件可以不用手动编写SQL语句实现分页。
    • PageHelper插件主要通过拦截Executor对象中的query方法来实现分页功能。当执行查询语句时,PageHelper会拦截该方法并解析传入的参数。

使用Mybatis的PageHelper分页插件实现分页步骤:

  • 1.查询之前开启分页:PageHelper.startPage( 3,2)
    • 3:表示当前页数
    • 2:表示每页显示的条数
  • 2.查询功能之后获取分页相关信息:PageInfo<Emp> pageInfo=new PageInfo<>(emps, 5)
    • emps:表示分页数据。
    • 5:当前导航分页的数量
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会敲代码的小张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值