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)trim、foreach,以下是我截取的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)if、where、set
<?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,即使用二级缓存,那么如果在数据库中修改了数据,而缓存数据还是原来的,这个时候就会出现脏读。