MyBatis
文章介绍:
一共不到8000字,一天之内可以快速学会mybatis的增删改查,
以及经常使用的操作,不讲废话,只将眼光聚焦到实操上,也可以搭配黑马的视频观看
看完之后,可以自己找个mybatis源码课继续学习
,但是一般的业务代码也只用到文章大部分内容
Mybatis是一款半ORM的持久层框架,简化JDBC的框架
一、快速入门
- 创建SQL表
- 编写MyBatis配置文件
- 编写SQL语句
- java定义POJO类
- SqlSessionFactory对象,获取SqlSession
- 执行Sql语句
- 释放资源
二、mapper代理开发
MyBtais使用mapper代理开发三个步骤:
- 定义mapper接口方法
- 定义SQL语句,其实就是写mapper.xml
- 调用者生成mapper 实例化对象,来进行操作
-
主要记得mapper接口要和resources目录下的mapper.xml一个目录;
-
如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载。也就是将核心配置文件的加载映射配置文件的配置修改为
<mappers>
<!--加载sql映射文件-->
<!-- <mapper resource="com/itheima/mapper/UserMapper.xml"/>-->
<!--Mapper代理方式-->
<package name="com.it.mapper"/>
</mappers>
重复性高的sql语句,在mapper.xml中,使用sql标签,定义sql片段。
三、难点业务
难点1:遇到数据库表字段与实体类属性名名称不一致,如何处理
1. SQL字段起别名
使用sql标签定义statement片段,将数据库字段as成实体类属性名。在statement中include进来。
例如:
<sql id="brand_column">
id, brand_name as brandName, company_name as companyName, ordered, description, status
</sql>
<select id="selectAll" resultType="brand">
select
<include refid="brand_column" />
from tb_brand;
</select>
2. ResultMap 封装结果集,实现数据库字段和实体类属性的映射关系
实现多字段数据库表只有些许字段需要对应修改,完成不一致的属性名和列名的映射
例如:
<resultMap id="brandResultMap" type="brand">
<!--
id:完成主键字段的映射
column:表的列名
property:实体类的属性名
result:完成一般字段的映射
column:表的列名
property:实体类的属性名
-->
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<select id="selectAll" resultMap="brandResultMap">
select *
from tb_brand;
</select>
难点2: where条件如何添加参数
1. sql语句参数占位符使用
#{}
:推荐使用,在sql语句中是?
存在,就是jdbc的PreparedStatement
${}
:拼接sql语句,存在sql注入问题,底层就是Statement
- 使用时机:参数传递用
#{}
;对于可变列名、表名用${},
但是实际中没什么用
2.parameterType使用
parameterType,对于有参数的mapper接口,一般在xml中可以省略,框架会自动封装。
例子:
/*
* id:唯一标识符
* parameterType:传递参数类型
* resultMap:返回类型
*/
<select id="selectById" parameterType="int" resultMap="brandResultMap">
select *
from tb_brand where id = ${id};
</select>
3.SQL语句中特殊字段处理
- 使用xml的转义字符:例如
<
就是<
的转义字符。 - <![CDATA[内容]]>,内容里面就写有歧义的内容
4. 总结例子
/*
* id:唯一标识符
* parameterType:传递参数类型,可以省略
* resultMap:返回类型
*/
<select id="selectById" parameterType="int" resultMap="brandResultMap">
select *
from tb_brand where id
<![CDATA[
<
]]>
#{id};
</select>
难点3: 多条件查询
1. 重点:
条件需要模糊查询
2. mapper接口参数接受
-
散装参数接受
使用
@Param("参数名称")
注解标记每一个参数,在映射配置文件中就需要使用#{参数名称}
进行占位,两个名称要一致。
代码:
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName,@Param("brandName") String brandName);
- 实体类封装参数
保证SQL语句的占位参数名称#{参数名称}
跟实体类属性名一致就行了
List<Brand> selectByCondition(Brand brand);
- map封装参数
保证map集合的key跟sql的占位参数名称#{参数名称}
一致就行了
List<Brand> selectByCondition(Map map);
3.sql语句编写
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where status = #{status}
and company_name like #{companyName}
and brand_name like #{brandName}
</select>
记得占位参数名称#{"参数名称"}
与三种方式要对应上。
4.调用
在调用中,要实现模糊查询,应该在调用时封装参数
// 处理参数
companyName = "%" + companyName + "%";
brandName = "%" + brandName + "%";
难点4: 添加数据
1.接口方法
参数使用实体类对象
void add(Object obj);
2.sql语句
<insert id="add">
insert into tb_brand (brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
3.提交事务
-
SqlSession sqlSession = sqlSessionFactory.openSession(true); //设置自动提交事务,这种情况不需要手动提交事务了
-
sqlSession.commit();//手动提交事务
4.主键返回
在业务中,可能需要主键注入到对象中,融合再读取作为其他的外键
所以,我们要修改mapper里面的代码
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into tb_brand (brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
新增的两个属性
useGeneratedKeys
:是够获取自动增长的主键值。true表示获取keyProperty
:指定将获取到的主键值封装到实体类对象哪儿个属性里,比如写的是"id
",就类似于写到brand.id
上
难点4: 删除单条数据
1.编写接口方法
在 Mapper 接口中定义根据id删除方法。
/**
* 根据id删除
*/
void deleteById(int id);
2 编写SQL语句
在 Mapper.xml 映射配置文件中编写删除一行数据的 statement
<delete id="deleteById">
delete from tb_brand where id = #{id};
</delete>
四、动态sql
1.动态多条件查询
1. 描述
在业务中,用户存在只填写一个信息,进行查询的情况,
需要我们动态去拼接statement
2.if标签
- 使用if标签,实现条件判断,逻辑表达式写在
test=" condition "
里面。 - 例子:
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where
<if test="status != null">
and status = #{status}
</if>
<if test="companyName != null and companyName != '' ">
and company_name like #{companyName}
</if>
<if test="brandName != null and brandName != '' ">
and brand_name like #{brandName}
</if>
</select>
3. where 标签
在上小节内容中,还存在一个问题,如果status条件不通过,会导致sql语句存在语法问题,有两种方法解决这个逻辑运算符问题
- 使用恒等式 ,例如 条件中加入
1=1
,每个条件都用and连接
<select ...
where 1=1
<if test="status != null">
and status = #{status}
....
</select>
- MyBatis中使用where标签能帮我们解决这个问题,会自动判断语句,在这个例子中,会自动帮我消去多余的and。
例子:
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
<where>
<if test="status != null">
and status = #{status}
</if>
<if test="companyName != null and companyName != '' ">
and company_name like #{companyName}
</if>
<if test="brandName != null and brandName != '' ">
and brand_name like #{brandName}
</if>
</where>
</select>
2.动态单条件查询
1.编写mapper接口方法
由于是可选条件,所以采用传入对象方法
/**
* 单条件动态查询
* @param brand
* @return
*/
List<Brand> selectByConditionSingle(Brand brand);
2. 编写sql方法
<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
<where>
<choose><!--相当于switch-->
<when test="status != null"><!--相当于case-->
status = #{status}
</when>
<when test="companyName != null and companyName != '' "><!--相当于case-->
company_name like #{companyName}
</when>
<when test="brandName != null and brandName != ''"><!--相当于case-->
brand_name like #{brandName}
</when>
</choose>
</where>
</select>
当然没有where标签时候是下面这样
<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
where
<choose><!--相当于switch-->
<when test="status != null"><!--相当于case-->
status = #{status}
</when>
<when test="companyName != null and companyName != '' "><!--相当于case-->
company_name like #{companyName}
</when>
<when test="brandName != null and brandName != ''"><!--相当于case-->
brand_name like #{brandName}
</when>
<otherwise><!--相当于default-->
1=1
</otherwise>
</choose>
where
</select>
3.动态update
1. 编写接口方法
/**
* 修改
*/
int update(Brand brand);
上述方法参数 Brand 就是封装了需要修改的数据,而id肯定是有数据的,
这也是和添加方法的区别,而且update会返回受影响行数
2.动态sql语句
<update id="update">
update tb_brand
<set>
<if test="brandName != null and brandName != ''">
brand_name = #{brandName},
</if>
<if test="companyName != null and companyName != ''">
company_name = #{companyName},
</if>
<if test="ordered != null">
ordered = #{ordered},
</if>
<if test="description != null and description != ''">
description = #{description},
</if>
<if test="status != null">
status = #{status}
</if>
</set>
where id = #{id};
</update>
set标签的作用
- 解决逗号的问题
- 解决防止条件都不成立的问题
4.批量删除(使用动态SQL)
用到的sql:delete from table where id in (?,?,?);
,其中的?是可变的
1.编写接口方法
在 Mapper 接口中定义删除多行数据的方法。
/**
* 批量删除
*/
void deleteByIds(int[] ids);
/**
* 使用@param注解,来重新定义map的key的名字
*/
void deleteByIds(@param("ids")int[] ids)
参数是一个数组,数组中存储的是多条数据的id
2.编写SQL语句
在 Mapper.xml 映射配置文件中编写删除多条数据的 statement。
编写SQL时需要遍历数组来拼接SQL语句。Mybatis 提供了 foreach 标签供我们使用
foreach
标签
用来迭代任何可迭代的对象(如数组,集合)。
collection
属性:- mybatis会将数组参数,封装为一个Map集合。
- 默认:
array = 数组
- 使用
@Param
注解改变map集合的默认key的名称,"自定义名称"
取代"array"
item
属性:本次迭代获取到的元素。separator
属性:集合项迭代之间的分隔符。foreach 标签不会错误地添加多余的分隔符。也就是最后一次迭代不会加分隔符。open
属性:该属性值是在拼接SQL语句之前拼接的语句,只会拼接一次close
属性:该属性值是在拼接SQL语句拼接后拼接的语句,只会拼接一次
<delete id="deleteByIds">
delete from tb_brand where id
in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
;
</delete>
五、参数传递
总结以上,我们可以发现,接口方法编写的时候,为什么有的地方要加@param注解,有的地方不加,而且为什么加@param注解后,就可以使用其值,如果不加@param注解,能否表示占位参数呢?我们根据 MyBatis底层的类,可以总结以下规律
1.多个参数
Mybatis 会将这些参数封装成 Map 集合对象,值就是参数值,不加@param注解时,每个参数会加两个key,例如参数1,会加
map.put(“arg0”,参数值1);
map.put(“param1”,参数值1);
使用 @Param 注解后,Mybatis 会将 arg 开头的键名替换为对应注解的属性值。
add(@Param("name")String name,...)
map.put(“name”,参数值1);
map.put(“param1”,参数值1);
2.单个参数
-
POJO
类型直接使用。要求 属性名 和 参数占位符名称 一致
-
Map
集合类型直接使用。要求 map集合的键名 和 参数占位符名称 一致
-
Collection
集合类型Mybatis 会将集合封装到 map 集合中,如下:
map.put(“arg0”,collection集合);
map.put(“collection”,collection集合;
可以使用 @Param 注解替换map集合中默认的 arg 键名。
-
List
集合类型Mybatis 会将List集合封装到 map 集合中,如下:
map.put(“arg0”,list集合);
map.put(“collection”,list集合);
map.put(“list”,list集合);
可以使用 @Param 注解替换map集合中默认的 arg 键名。
Array
类型
Mybatis 会将集合封装到 map 集合中,如下:
map.put(“arg0”,数组);
map.put(“array”,数组);
可以使用 @Param 注解替换map集合中默认的 arg 键名。
-
其他类型
比如int类型,参数占位符名称 叫什么都可以。尽量做到见名知意
六、注解开发
查询 :@Select
添加 :@Insert
修改 :@Update
删除 :@Delete
注解完成简单功能,配置文件完成复杂功能。