0 准备环境
0.1 创建数据库表tb_brand
drop table if exists tb_brand;
creat table tb_brand
(
-- id 主键
id int primary key auto_increment,
-- 品牌名称
brand_name varchar(20),
-- 企业名称
company_name varchar(20),
-- 排序字段
ordered int,
-- 描述信息
description varchar(100),
-- 状态:0:禁用 1:启用
state int
);
0.2 创建实体类Brand类
public class Brand {
// id 主键
private Integer id;
// 品牌名称
private String brandName;
// 企业名称
private String companyName;
// 排序字段
private Integer ordered;
// 描述信息
private String description;
// 状态:0:禁用 1:启用
private Integer status;
//省略 setter and getter。自己写时要补全这部分代码
}
1 查询所有数据
1.1 编写接口方法(Mapper接口)
在BrandMapper接口中定义方法:
List<Brand> selectALL();
1.2 编写SQL语句(SQL映射文件)
在resources下创建BrandMapper.xml映射配置文件
<mapper namespace="com.example.mapper.BrandMapper">
<select id="selectAll" resultType="brand">
select *
from tb_brand;
</select>
</mapper>
这里resltType参数为brand,需在mybatis-config.xml文件中设置别名(见上一章)
1.3 起别名解决表中字段和类属性名不一致
表中的字段名
brand_name和类中的属性名
brandName不一致,导致查询失败,可以在编写查询语句时为字段起别名:
<select id="selectAll" resultType="brand">
select
id, brand_name as brandName, company_name as companyName, ordered, description, status
from tb_brand;
</select>
- SQL片段
Step1:将需要复用的SQL片段抽取到 sql 标签
中
<sql id="brand_column">
id, brand_name as brandName, company_name as companyName, ordered, description, status
</sql>
Step2:在原SQL语句中进行引用
<select id="selectAll" resultType="brand">
select
<include refid="brand_column" />
from tb_brand;
</select>
1.4 使用resultMap解决问题
在SQL映射配置文件中使用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>
SQL语句正常编写,resultType
参数改为resultMap
参数(上面定义的resultMap
的id):
<select id="selectAll" resultMap="brandResultMap">
select *
from tb_brand;
</select>
2 单条件查询
2.1 编写接口方法(Mapper接口)
在BrandMapper接口中定义方法:
Brand selectById(int id);
2.2 编写SQL语句(SQL映射文件)
在 BrandMapper.xml 映射配置文件中编写 statement ,使用 resultMap
而不是使用 resultType
<select id="selectById" resultMap="brandResultMap">
select *
from tb_brand where id = #{id};
</select>
2.3 参数占位符
mybatis提供了两种参数占位符:
- #{} :执行
SQL
时,会将 #{} 占位符替换为?,将来自动设置参数值。从上述例子可以看出使用#{} 底层使用的是PreparedStatement
- ${} :拼接
SQL
。底层使用的是Statement
,会存在SQL注入问题。
2.4 SQL语句中特殊字段处理
因为映射配置文件是xml类型的问题,而 > < 等这些字符在xml中有特殊含义,所以此时我们需要将这些符号进行转义,可以使用以下两种方式进行转义:
1、转义字符
<select id="selectById" resultMap="brandResultMap">
select *
from tb_brand
where id < #{id}; // < 即相当于 <
</select>
2、
<select id="selectById" resultMap="brandResultMap">
select *
from tb_brand
where id
<![CDATA[
=
]]>
#{id};
</select>
3 多条件查询
3.1 编写接口方法(Mapper接口)
Mybatis针对多参数有多种实现
- 使用
@Param("参数名称")
标记每一个参数,在映射配置文件中就需要使用 #{参数名称} 进行占位
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName, @Param("brandName") String brandName);
- 将多个参数封装成一个 实体对象 ,将该实体对象作为接口的方法参数。该方式要求在映射配置文件的SQL中使用
#{内容}
时,里面的内容必须和实体类属性名
保持一致
List<Brand> selectByCondition(Brand brand);
- 将多个参数封装到map集合中,将map集合作为接口的方法参数。该方式要求在映射配置文件的SQL中使用
#{内容}
时,里面的内容必须和map集合中键
的名称一致
List<Brand> selectByCondition(Map map);
3.2 编写SQL语句(SQL映射文件)
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where status = #{status}
and company_name like #{companyName}
and brand_name like #{brandName}
</select>
3.3 动态SQL
上述功能实现存在很大的问题。用户在输入条件时,肯定不会所有的条件都填写,而Mybatis对动态SQL
有很强大的支撑:
- 使用
if
标签和where
标签
<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>
注意:需要给每个条件前都加上 and 关键字。
4 单条件查询(动态SQL)
在查询时只能选择 品牌名称 、 当前状态 、 企业名称 这三个条件中的一个,但是用户到底选择哪儿一个,我们并不能确定。这种就属于单个条件的动态SQL语句。
4.1 编写接口方法(Mapper接口)
List<Brand> selectByConditionSingle(Brand brand);
4.2 编写SQL语句(SQL映射文件)
- 使用
choose
标签和when
标签(类似于switch
语句)
<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>
5 添加数据
参数:除了id之外的所有的数据。id对应的是表中主键值,而主键我们是自动增长生成的。
5.1 编写接口方法(Mapper接口)
void add(Brand brand);
5.2 编写SQL语句(SQL映射文件)
<insert id="add">
insert into tb_brand (brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
添加完数据需要提交事务 sqlSession.commit();
5.3 添加-主键返回
在数据添加成功后,有时候需要获取插入数据库数据的主键(主键是自增长),也就是add(Brand brand)
中的参数brand
类的属性id
会被自动赋值
<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>
在 insert 标签上添加如下属性:
- useGeneratedKeys:是够获取自动增长的主键值。true表示获取
- keyProperty :指定将获取到的主键值封装到哪儿个属性里
这样的话,往数据库添加完数据后,brand实体类的id
也被赋值了
//接收参数
int status = 1;
String companyName = "波导手机";
String brandName = "波导";
String description = "手机中的战斗机";
int ordered = 100;
//封装对象,这时候id属性是没有值得
Brand brand = new Brand();
brand.setStatus(status);
brand.setCompanyName(companyName);
brand.setBrandName(brandName);
brand.setDescription(description);
brand.setOrdered(ordered);
brandMapper.add(brand);
Integer id = brand.getId(); // 这时候id会被赋值
System.out.println(id);
6 修改数据
6.1 编写接口方法(Mapper接口)
void update(Brand brand);
6.2 编写SQL语句(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 标签可以用于动态包含需要更新的列,忽略其它不更新的列。
7 删除一行数据
7.1 编写接口方法(Mapper接口)
void deleteById(int id);
7.2 编写SQL语句(SQL映射文件)
<delete id="deleteById">
delete from tb_brand where id = #{id};
</delete>
8 批量删除数据
8.1 编写接口方法(Mapper接口)
void deleteByIds(int[] ids);
参数是一个数组,数组中存储的是多条数据的id
8.2 编写SQL语句(SQL映射文件)
编写SQL时需要遍历数组来拼接SQL语句。Mybatis 提供了 foreach 标签供我们使用
foreach 标签:
用来迭代任何可迭代的对象(如数组,集合)。
-
collection
属性:- mybatis会将数组参数,封装为一个Map集合。
默认:array
= 数组
使用@Param
注解改变map
集合的默认key
的名称(见下)
- mybatis会将数组参数,封装为一个Map集合。
-
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>
假如数组中的id数据是{1,2,3},那么拼接后的sql语句就是:
delete from tb_brand where id in (1,2,3);
9 Mybatis参数传递
Mybatis 接口方法中可以接收各种各样的参数,如下:
- 多个参数
- 单个参数:单个参数又可以是如下类型
- POJO 类型
- Map 集合类型
- Collection 集合类型
- List 集合类型
- Array 类型
- 其他类型
9.1 多个参数
我们在接口方法中定义多个参数,Mybatis 会将这些参数封装成 Map
集合对象,值就是参数值,而键在没有使用 @Param
注解时有以下命名规则:
- 以
arg
开头 :第一个参数就叫 arg0,第二个参数就叫 arg1,以此类推。如:
map.put("arg0",参数值1);
map.put("arg1",参数值2);
- 以
param
开头 : 第一个参数就叫param1
,第二个参数就叫param2
,依次类推。如:
map.put("param1",参数值1);
map.put("param2",参数值2);
在映射配合文件的SQL语句中使用用 arg
开头的和 param
书写,代码的可读性会变的特别差,此时可以使用 @Param
注解:
User select(@Param("username") String username, String password);
Mybatis 在封装 Map
集合时,键名就会覆盖arg0
参数,变成如下:
map.put("username",参数值1);
map.put("arg1",参数值2);
map.put("param1",参数值1);
map.put("param2",参数值2);
结论:以后接口参数是多个时,在每个参数上都使用 @Param
注解。这样代码的可读性更高。
9.2 单个参数
-
POJO 类型
直接使用。要求
属性名
和参数占位符名称
一致 -
Map 集合类型
直接使用。要求
map集合的键名
和参数占位符名称
一致 -
Collection 集合类型
Mybatis 会将集合封装到 map 集合中,如下:
map.put(“arg0”,collection集合);
map.put(“collection”,collection集合);可以使用
@Param
注解替换map集合中默认的 arg 键名。 -
List 集合类型
Mybatis 会将集合封装到 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类型,
参数占位符名称
叫什么都可以。尽量做到见名知意
10 注解实现CRUD
使用注解开发会比配置文件开发更加方便。如下就是使用注解进行开发
@Select(value = "select * from tb_user where id = #{id}")
public User select(int id);
注意:
- 注解是用来替换映射配置文件方式配置的,所以使用了注解,就不需要再映射配置文件中书写对应的
statement
Mybatis 针对 CRUD 操作都提供了对应的注解,已经做到见名知意。如下:
- 查询 :
@Select
- 添加 :
@Insert
- 修改 :
@Update
- 删除 :
@Delete
所以,注解完成简单功能,配置文件完成复杂功能(动态SQL)。