【Mybatis笔记】总结Mybatis的面试题

Mybatis是什么?

MyBatis 是一个可以自定义 SQL、存储过程和高级映射的持久层框架,它的内部封装了JDBC,是一个灵活性较高的半ORM(对象关系映射)框架。

Mybatis的XML映射文件中不同的XML映射文件,id是否可以重复?

不同的xml文件,如果配置了namespace,那么id可以重复,如果没有配置namespace,那么id不可以重复。

#{}和${}的区别是什么?

#{}是预编译处理,${}是字符串替换。

Mybatis是如何将sql执行结果封装为目标对象并返回的?

(1)可以使用 标签

(2)可以使用sql列的别名

mybaties中模糊查询like语句的写法

模糊查询’%’ #{keyWord} '%'防止sql注入(占位符) '%${value}%'用于拼接parameterType=“String”

(1)用#{value}可以防止Sql注入

select * from foo where bar like #{value}

(2)用${value},有Sql注入的风险

select * from foo where bar like “%”${value}"%"

Mybatis动态sql标签有哪些?

(1)trimforeach,以下是我截取的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.swjd.mapper.UserMapper">
    <!--prefixOverrides的作用是去掉第一个and或者是or-->
    <select id="selectTrim" resultType="User">
        select * from user
        <trim prefix="WHERE" prefixOverrides="AND|OR">
            <if test="userName!=null and userName!=''">
                and username like '%' #{userName} '%'
            </if>
            <if test="sex!=null and sex!=''">
                and sex like '%' #{sex} '%'
            </if>
        </trim>
    </select>
    <update id="update">
        update user
        <trim prefix="set" suffixOverrides=",">
            <if test="userName!=null and userName!=''">
                username=#{userName},
            </if>
            <if test="sex!=null and sex!=''">
                sex=#{sex},
            </if>
            <if test="address!=null and address!=''">
                address=#{address},
            </if>
            <if test="birthDay!=null and birthDay!=''">
                birthDay=#{birthDay},
            </if>
        </trim>
        where  id=#{id}
    </update>
    <!--
    collection是要遍历的类型
    item是循环元素
    separator是分隔符
    1.<sql id="命名">
    相同的代码
    </sql>
    2.引入代码块
    <include refid="命名" />
    -->
    <delete id="deletes" >
        delete from user where id in
        <foreach collection="list" open="(" close=")" separator="," item="aaa">
            #{aaa}
        </foreach>
    </delete>

    <delete id="deletes2" >
        delete from user where
        <foreach collection="array" separator="or" item="id">
           id = #{id}
        </foreach>
    </delete>
</mapper>

(2)ifwhereset

<?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.swjd.mapper.UserMapper">
    <select id="selectUserNameAndS" resultType="User">
        select * from user where 1=1
        <if test="userName!=null and userName!=''">
            and username like '%' #{userName} '%'
        </if>
        <if test="sex!=null and sex!=''">
            and sex like '%' #{sex} '%'
        </if>
    </select>
    <!--where的作用:可以在语句之后添加多余关键字 可以去掉多余的and和or-->
    <select id="selectWhere" resultType="User">
        select * from user
        <where>
            <if test="userName!=null and userName!=''">
                and username like '%' #{userName} '%'
            </if>
            <if test="sex!=null and sex!=''">
                and sex like '%' #{sex} '%'
            </if>
        </where>
    </select>
    <!--set的作用:在sql语句后加入set可以去掉多余的逗号-->
    <update id="update">
        update user
        <set>
            <if test="userName!=null and userName!=''">
                username=#{userName},
            </if>
            <if test="sex!=null and sex!=''">
                sex=#{sex},
            </if>
            <if test="address!=null and address!=''">
                address=#{address},
            </if>
            <if test="birthDay!=null and birthDay!=''">
                birthDay=#{birthDay}
            </if>
        </set>
        where  id=#{id}
    </update>
</mapper>

Mybatis的优点有哪些?

(1)基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理,高解耦性

(2)与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接。

(3) 很好的与各种数据库兼容。

Mybatis的缺点?

(1)SQL语句的编写工作量较大。

(2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

实体类中的属性名和表中的字段名不一样怎么处理?

(1)可以给Sql语句设置和类中的属性名一样。

(2)通过来映射字段名和实体类属性名

在mybatis的配置文件中,可以通过typeAliases标签来设置实体类的别名。

<!--实体类取别名-->
    <typeAliases>
        <package name="com.swjd.bean"/>
    </typeAliases>
    <!--引入映射文件-->
    <mappers>
        <!--<mapper resource="com/swjd/mapper/UserMapper.xml"></mapper>-->
        <package name="com.swjd.mapper"/>
    </mappers>

MyBatis操作数据库时的接口方法中,如果传入的参数名和动态sql中使用时不一致,则需要使用==@Param==注解修饰。

关联映射:

(1)一对多collection

(2)多对一 association

<!--配置多对一-->
    <resultMap id="sselectMap" type="Students">
        <id column="s_id" property="sId"/>
        <result column="s_name" property="sName"/>
        <result column="s_age" property="sAge"/>
        <result column="s_email" property="sEmail"/>
        <result column="class_id" property="classId"/>
        <!--有一个班级信息-->
        <association property="classes" javaType="Classes">
            <id column="c_id" property="cId"/>
            <result column="c_name" property="cName"/>
        </association>
    </resultMap>
    <select id="getStudentsById" resultMap="sselectMap">
        select * from students inner join classes c
        on students.class_id = c.c_id
        where s_id=#{sId}
    </select>

Mybatis动态sql有什么用?执行原理?

Mybatis动态sql可以在Xml映射文件内,以标签的形式编写动态sql,执行原理是根据表达式的值 完成逻辑判断并动态拼接sql的功能。

如何获取自动生成的(主)键值?

如果采用自增长策略,自动生成的键值在 insert 方法执行完后可以被设置到传入的参数对象中。
usegeneratedkeys=”true” keyproperty=”id”

<!--增加 useGeneratedKeys=开启自增长注解映射 ,keyProperty="主键的属性名"-->
    <insert id="zengJia" useGeneratedKeys="true" keyProperty="id">
       insert into user values(null ,#{userName},#{birthDay},#{sex},#{address})
    </insert>

MyBatis性能优化(缓存机制)

1.什么是延迟加载(按需加载)

延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。需要关联信息时再去按需加载关联信息。这样会大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

1.1 设置延迟加载(配置问题使用代码演示)

Mybatis默认是没开启延迟加载功能的,我们需要手动开启。

(1)需要在mybatis-config.xml文件中,在settings标签中开启延迟加载功能。
全局配置:

<!--实现延迟加载(按需加载)第一步-->
    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

局部配置
fetchType是可以注明在association 和 collection里的,选值为eager和lazy,就是为了方便我们结合aggressiveLazyLoading(false)来配合使用的,让延迟加载发挥到极致,即只加载我需要的!

在这里插入图片描述
在最新官方MyBatis文档里,有上面这2个属性,一个是延迟加载,一个是分层加载。
lazyLoadingEnabled 默认值为false,那么在有级联关系的resultMap里,查询后会加载出所有的级联关系,当然有时候我们并不需要这些所有的时候,我们就可以应用到延迟加载给我们带来的好处了。
aggressiveLazyLoading默认值是true,这里我称之为分层加载,大概意思是如果它为true,那么当我使用了延迟加载,要么所有级联都不加载,要么如果我加载一个,其他都得加载.
aggressiveLazyLoading值是false 那么就是按需加载,如果是true表示只要使用一个级联对象,就全部加载!
在这里插入图片描述
如果全局和局部同时生效,那么就近原则,局部生效!

2.MyBatis缓存(面试题)

Cache 缓存
在这里插入图片描述
缓存中有,先查询缓存。缓存中没有,那么查询数据库。这样的话不用每次都查询数据库。减轻数据库的压力。提高查询效率!!!

第一次查询的时候,由于缓存中没有,那么去查询数据库返回给客户端。同时还会把这个次查询的数据放入缓存。
第二次查询同样的数据时候,发现缓存中曾经有查询过的数据,那么直接从缓存中读取。不必再次查询数据库,减轻数据库压力!

2.1 MyBatis缓存分析

mybatis提供查询缓存,如果缓存中有数据就不用从数据库中获取,用于减轻数据压力,提高系统性能。
在这里插入图片描述
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

Mybatis的缓存,包括一级缓存和二级缓存
一级缓存指的就是sqlsession,在sqlsession中有一个数据区域,是map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询出的结果对象。
一级缓存是session级别的,同一个session! 1级缓存是系统自带,不需要手动开启!

二级缓存指的就是同一个namespace下的mapper,二级缓存中,也有一个map结构,这个区域就是二级缓存区域。二级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。二级缓存中的value,就是查询出的结果对象。
二级缓存,可以跨session!二级缓存是要配置,然后手动开启!

简单来说
一级缓存是默认使用的。
二级缓存需要手动开启。

Map<String,Object> key 缓存标志 Value 缓存的数据

开启二级缓存

Mybatis默认是没有开启二级缓存
1.在核心配置文件myBatis-config.xml中加入以下内容(开启二级缓存总开关):
在settings标签中添加以下内容:
在这里插入图片描述
2.在StudentMapper映射文件中,加入以下内容,开启二级缓存:
在这里插入图片描述

3.实现序列化
在这里插入图片描述
由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象执行序列化。
缓存默认是存入内存中,但是如果需要把缓存对象存入硬盘那么久需要序列化(实体类要实现)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果该类存在父类,那么父类也要实现序列化。
在这里插入图片描述

禁用二级缓存

该statement中设置useCache=false,可以禁用当前select语句的二级缓存,即每次查询都是去数据库中查询,默认情况下是true,即该statement使用二级缓存。
在这里插入图片描述

刷新二级缓存

该statement中设置flushCache=true可以刷新当前的二级缓存,默认情况下如果是select语句,那么flushCache是false。如果是insert、update、delete语句,那么flushCache是true
如果查询语句设置成true,那么每次查询都是去数据库查询,即意味着该查询的二级缓存失效。
如果查询语句设置成false,即使用二级缓存,那么如果在数据库中修改了数据,而缓存数据还是原来的,这个时候就会出现脏读。
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46319117/article/details/105343672
今日推荐