Mybatis
📑前言
本文主要是【Mybatis】——Mybatis面经的文章,如果有什么需要改进的地方还请大佬指出⛺️
🎬作者简介:大家好,我是听风与他🥇
☁️博客首页:CSDN主页听风与他
🌄每日一句:狠狠沉淀,顶峰相见
目录
- Mybatis
- 📑前言
- 1.缓存
- 1.1一级缓存
- 1.3二级缓存
- 1.4在配置文件中,开启二级缓存的总开关
- 2.在mapper映射文件中开启二级缓存
- 2.mybatis是半自动ORM映射工具,它与全自动的区别?
- 3.Mybatis和Hibernate有哪些不同?
- 4.Mybatis中#{ }和${ }的区别
- 5.resultmap与resulttype的区别
- 📑文章末尾
1.缓存
- mybatis对缓存提供支持,一级缓存是默认使用的,二级缓存需要手动开启。
区别:
- 一级缓存的作用域是一个sqlsession内;
- 二级缓存作用域是针对mapper进行缓存;
1.1一级缓存
- 在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SqlSession第一次查询后,Mybatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。
- 一级缓存执行commit,close,增删改等操作,就会清空当前的一级缓存,当对SqlSession执行更新操作(update,delete,insert)后执行commit时,不仅清空自身的一级缓存(执行更新操作的效果),也清空二级缓存(执行commit()的效果)
1.3二级缓存
- 二级缓存指的是同一个namespace下的mapper,二级缓存中,也有一个map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句,条件,statement等信息组成一个唯一值,一级缓存中的value,就是查询出的结果对象。
1.4在配置文件中,开启二级缓存的总开关
<setting name="cacheEnabled" value="true" />
2.在mapper映射文件中开启二级缓存
<cache eviction="FIFO" flushInterval="60000" size="512"
readOnly="true"/>
禁用缓存
<select id="findAllPets" resultMap="petsMap" useCache="false">select * from pets
</select>
刷新缓存
- 在印射文件中,属性: flushCache='true’刷新缓存,在查询语句中,默认值是falsh,在新增删除修改语句中,默认值是true(清空缓存)
2.mybatis是半自动ORM映射工具,它与全自动的区别?
- hibernate属于全自动ORM映射工具,使用hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称为半自动ORM映射工具。
3.Mybatis和Hibernate有哪些不同?
- Mybatis和Hibernate不同,它不完全是一个ORM框架,因为Mybatis需要程序员自己编写sql语句,不过mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。
- Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一旦需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。
4.Mybatis中#{ }和${ }的区别
-
相同点:都能取到变量的值
-
不同点:#{ }可以实现预编译,会先把#{ }编译成?,在执行时再取值,可以防止sql注入。
-
${ }是直接进行字符串替换
-
#符号解析:主要在数据类型检查和安全检查两部分。
- 数据类型检查表现在:若检测到为数值类型,就不加引号,若检测到为字符串类型,就加上引号,即’?’
- 安全检查表现在:若变量的值带有引号,会对引号进行转义处理,这样可以防止sql注入。
-
#符号的应用场景:需要在sql映射文件中动态拼接sql时的开发场景,比如传入多个变量进行条件查询,传入一个pojo进行数据插入等。
-
符号解析: { }符号解析: 符号解析:符号主要用于传入的参数是sql片段的场景下,会直接进行字符串替换,完成了sql的拼接,
-
比如我们不在sql映射文件中利用mybatis的动态sql来拼接sql,而是在java代码中去动态的拼接sql,然后将拼接的sql片段作为变量传入sql映射文件。上面也说了$符号只是进行字符串的替换,如果我们传入一个sql片段的话,相当于直接进行了sql拼接,就不用在sql映射文件中利用mybatis提供的动态sql标签来拼接sql了。甚至可以这样:
<select id="getUserPage" resultType="com.ymxx.oa.bean.User">${sql片段} </select>
*对于这样外部传入的sql,就不能使用#{},上面也说了,#{}会进行预编译,检测到该sql片段是个字符串,就会加上引号,即’sql片段’,这样就是字符串了而不是sql,执行会报错。*
依据$适用于传入sql片段的情况,我们可以将数据表字段名、表名、数据库名等传入,来进行sql拼接,如:
$符号的应用场景:
比如:select ${columns} from ${tableName},假设columns变量的值是userName,age 。tableName变量的值是user,那么该sql语句就会被解析成:select userName,age from user
比如有这样一个需求:对于后台管理系统的table列,想让用户选择展示哪些列,不展示哪些列,或者根据权限来分配不同的用户可以看到哪些列?
这个需求正好用到了 符号,我们可以将每个用户对于一个 t a b l e 能看到哪些列,存储到数据表中,对该数据表进行 c r u d ,每次展示列表的时候,先根据用户 I D 和 t a b l e 类型,到数据表中查询该用户对该 t a b l e 能看到的列名 ( 字段名 ) 列表,然后将该字段名列表作为 s q l 片段传入 m y b a t i s 进行查询,此时就必须得用到 符号,我们可以将每个用户对于一个table能看到哪些列,存储到数据表中,对该数据表进行crud,每次展示列表的时候,先根据用户ID和table类型,到数据表中查询该用户对该table能看到的列名(字段名)列表,然后将该字段名列表作为sql片段传入mybatis进行查询,此时就必须得用到 符号,我们可以将每个用户对于一个table能看到哪些列,存储到数据表中,对该数据表进行crud,每次展示列表的时候,先根据用户ID和table类型,到数据表中查询该用户对该table能看到的列名(字段名)列表,然后将该字段名列表作为sql片段传入mybatis进行查询,此时就必须得用到符号,而不能用#符号了。
符号的 s q l 注入问题:用 符号的sql注入问题: 用 符号的sql注入问题:用{}时要特别注意sql注入的风险,如果该sql片段是根据用户的输入拼接的,要注意检查sql注入的问题,防止数据的泄露与丢失!
5.resultmap与resulttype的区别
- resultmap与resulttype的区别为:对象不同,描述不同,类型适用不同。
- 简单来说,就是resultmap和resulttype功能差不多,但是resultmap功能更强大。
resultType:
-
使用resultType进行输出映射时,至少查询出来的列名和pojo(简单实例对象)中的属性名一致,该列才可以映射成功。
-
int,string,list中元素的类型
<select id="count" resultType="int">select count(id) from t_paper as pLEFT JOIN t_type as tONp.type_id=t.id</select>
resultMap:
- resultMap可以实现将查询结果映射为复杂类型的pojo,简单来说就是,resultType解决不了的,都交给resultMap来解决。在使用resultMap之前我们需要先定义一个符合当前需求的resultMap.
<resultMap id="paperResult" type="Paper"><!-- column:数据库字段名 property:实体的属(变量)名 --><result column="id" property="id"/> <result column="title" property="title"/><result column="type_id" property="typeId"/><result column="paper_summary" property="paperSummary"/><result column="paper_path" property="paperPath"/></resultMap><select id="selectPaperListByCondition" resultMap="paperResult">SELECTp.*, t.type_name from t_paper as pLEFT JOINt_type as tONp.type_id=t.idWHEREtitle='' and type_name=''<where><if test="title != null and title != ''">and title like '%${title}%'</if><if test="typeName != null and typeName != ''">and type_name=#{typeName}</if></where>limit #{start},#{size}</select>