一、基础介绍
介绍
MyBatis是一款支持定制化 SQL、存储过程以及高级映射的半自动化持久化层框架。 其可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录。
使用流程
使用MyBatis的流程:MySQL表——实体类——Mapper接口——xml映射文件
全局配置
可以在properties配置文件中配置数据库信息,包括driver、url、username、password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/ceshi?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true spring.datasource.username=root spring.datasource.password=****
二、xml映射文件
(一)<select>标签
注意:查询功能的标签必须设置resultType或resultMap之一
- resultType:设置默认的映射关系,即将查询到的字段,根据字段名自动匹配类属性,存在就赋值,不存在就不赋值;
- resultMap:设置自定义的映射关系,用于查询到的字段名和映射属性名不一致的情况;
(二)MyBatis获取参数值
1、获取方式
(1)${}
本质:以字符串拼接方式拼接SQL。此时如果是字符串类型或日期类型的字段进行赋值时,需要手动加单引号。
注意:
- 字符串拼接会导致SQL注入,并且要考虑加单引号,麻烦,一般不用
- 只有在特殊SQL,无法使用#{}时,包括模糊查询、批量删除、动态设置表名、添加自增主键等情况,不能添加单引号,必须使用${}
举例:
- 模糊查询:select * from t_user where username like "%"#{mohu}"%"或'%${mohu}%'或concat('%',#{mohu},'%');
- 批量删除:delete from t_user where id in (${ids});
- 动态设置表名:select * from ${tableName};
(2)#{}
本质:以占位符赋值方式拼接SQL,会自动添加单引号
注意:使用该种方式获取实际内容时,只和值以及位置有关,和参数名称无关。
2、需要获取参数值的情况
(1)mapper接口中的方法参数为单个的字面量类型
使用#{xxx}或'${xxx}'即可
(2)多个字面量类型的参数
该情况不能直接用参数名进行获取,可以用arg和param+编号的形式获取
注意:arg从0开始,param从1开始
(3)map集合类型的参数
用于多个参数情况,手动创建map集合,可通过#{map键名}的形式获取对应的值
(4)实体类类型的参数
访问形式和(3)相同,直接通过类的属性名(全小写)作为键名进行访问
(5)使用@Param标识参数
会默认将@Param标注的参数放在map集合中,可以通过(2)访问,也可以根据注解的命名来作为键名访问
(三)<insert>标签
属性包括:
- useGeneratedKeys:设置是否使用自增主键,true表示使用;
- keyProperty:设定作为自增主键的列名,将自增的主键的值赋值给某个属性;
示例:
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> insert into t_user values (null,#{username},#{password}) </insert>
(四)自定义映射resultMap
1、本质
相当于给字段设置别名,用于解决类属性名和数据库表字段名不一致的情况
2、基础标签:
主键id,普通属性result。通过映射关系中的属性名property和字段名column来配置映射关系
3、多对一映射关系:
- 在result中对property设置为xxx.xxx级联属性;
- 使用association,property:需要处理的属性名,javaType:该属性的Java类类型
- 分布查询
-
- 分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息settings:
-
-
- lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
- aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载
-
- 延迟加载的配置项:
-
- select:设置分布查询的sql的唯一标识,一般为mapper接口的全类名.方法名;
- column:设置分布查询的条件字段;
- fetchType:当开启了全局延迟加载之后,控制延迟加载的效果,lazy表示延迟加载,eager表示立即加载
4、一对多映射关系:
- 在resultMap中使用collection;
- 分布查询
三、动态SQL
1、if标签
用法:<if test="......">...</if>
2、where标签
与其他标签结合使用,没有满足条件的项,where失效不会添加到sql中
3、trim标签
- prefix/suffix:前缀/后缀标签,将标签属性的内容添加到trim标签前/后
- prefixOverrides/suffixOverrides:在trim标签中每个标签的前面或后面去除属性内容
4、choose、when、otherwise组合标签
相当于Java中的if、if else、else
5、foreach标签
属性:
- collection:设置要循环的数组或集合
- item:表示集合或数组中的每一个数据
- separator:设置循环体之间的分隔符,分隔符前后默认有一个空格
- open:设置foreach标签中的内容的开始符
- close:设置foreach标签中的内容的结束符
6、sql标签
作用:可以记录一段公共sql片段,在使用的地方通过include标签进行引入
引入方式:<include refid="sql标签的id"></include>
四、MyBatis缓存原理
1、一级缓存
- 默认开启,一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
- 失效的四种情况:
-
- (1) 不同的SqlSession对应不同的一级缓存
- (2) 同一个SqlSession但是查询条件不同
- (3) 同一个SqlSession两次查询期间执行了任何一次增删改操作
- (4) 同一个SqlSession两次查询期间手动清空了缓存
2、二级缓存
- 默认不开启,二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
- 开启条件:
-
- (1)在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
- (2)在映射文件中设置标签
- (3)二级缓存必须在SqlSession关闭或提交之后有效
- (4)查询的数据所转换的实体类类型必须实现序列化的接口
- 失效情况:
-
- 两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
3、三级缓存
三级缓存需要整合第三方的缓存插件才能使用。
五、具体案例:
<?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.example.springboot.mapper.CeshiMapper">
<resultMap id="BaseResultMap" type="com.example.springboot.model.Ceshi">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
</resultMap>
<sql id="Base_Column_List">
id, name
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from ceshi1
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete from ceshi1
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.example.springboot.model.Ceshi">
insert into ceshi1 (id, name)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="com.example.springboot.model.Ceshi">
insert into ceshi1
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="name != null">
name,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.example.springboot.model.Ceshi">
update ceshi1
<set>
<if test="name != null">
name = #{name,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.example.springboot.model.Ceshi">
update ceshi1
set name = #{name,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
</update>
</mapper>