四、MyBatis练习
4.1 配置文件实现 CRUD
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Id1Fc4nG-1663774584852)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829072356478.png)]
4.1.1 环境准备
1. 数据库表 tb_brand
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Esx8jLcD-1663774584853)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829073024601.png)]
2. 实体类 Brand
package pojo;
/**
* @Author 晨默
* @Date 2022/8/28 20:06
*/
public class Brand {
// id 主键
private Integer id;
// 品牌名称
private String brandName;
// 企业名称
private String companyName;
// 排序字段
private Integer ordered;
// 描述信息
private String description;
// 状态:0:禁用 1:启用
private Integer status;
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brandName='" + brandName + '\'' +
", companyName='" + companyName + '\'' +
", ordered=" + ordered +
", description='" + description + '\'' +
", status=" + status +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public Integer getOrdered() {
return ordered;
}
public void setOrdered(Integer ordered) {
this.ordered = ordered;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}
4.1.2 查询所有数据
1. 编写接口方法 BrandMapper
public interface BrandMapper {
/*
* 查询所有
* */
List<Brand> selectAll();
}
2. SQL 语句
创建名为 BrandMapper.xml 的映射配置文件
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.BrandMapper">
<!-- 查询所有数据 -->
<select id="selectAll" resultType="brand">
select *
from tb_brand;
</select>
</mapper>
3. 测试方法
MybatisTest 类中编写
@Test
public void testSelectById() throws IOException {
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行方法
List<Brand> brands = brandMapper.selectAll();
System.out.println(brands);
// 5. 释放资源
sqlSession.close();
}
测试结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OcfDWAzd-1663774584853)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829074405578.png)]
==出现问题:==有的数据没有封装成功
解决方式:
- 给字段起别名
- 使用 resultMap 定义字段和属性的映射关系。推荐使用
4. 使用 resultMap 解决问题
映射配置文件中使用 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语句则变为如下:
<!-- 查询所有数据 -->
<select id="selectAll" resultMap="brandResultMap">
select *
from tb_brand;
</select>
4.1.3 查询详情
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dRP8733r-1663774584854)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829081243811.png)]
查询某一行的数据,需要根据id进行查询
1. 接口方法——BrandMapper接口
/*
* 查看详情:根据id查询
* */
Brand selectById(int id);
2. SQL语句
<!-- 查询详情 -->
<select id="selectById" resultMap="brandResultMap">
select *
from tb_brand where id = #{id};
</select>
3. 测试方法
/*
* 查看详情:根据Id查询
* */
@Test
public void testSelectById() throws IOException {
// 接受参数,该id以后需要传递过来
int id = 1;
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行方法
Brand brand = brandMapper.selectById(id);
System.out.println(brand);
// 5. 释放资源
sqlSession.close();
}
测试结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uGbMhLH2-1663774584854)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829081919536.png)]
4. 参数占位符
-
#{} : 执行SQL时,会将 #{} 占位符替换为 ?。之后自动设置参数值。底层使用 PreparedStatement。一般使用#{}
-
${} : 拼接SQL时,底层使用 Statement,会存在SQL注入问题
5. paramterType 使用
对于有参数的mapper接口方法,映射配置文件中应该配置 ParamterType 来制定参数类型。不过改属性都可以省略。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VXo9aGRL-1663774584854)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829082701308.png)]
6. SQL特殊字段处理
<>等字符在xml文件中有特殊含义,需要进行转义
- 转义字符:
<
代表 < 字符 <![CDATA[内容]]>
4.1.4 多条件查询
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PmNFEnRU-1663774584855)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829083253457.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-snLT3E1W-1663774584855)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829083313578.png)]
1. 接口方法
- 使用 @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);
2. 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. 测试方法
/*
* 多条件查询
* */
@Test
public void testSelectByCondition() throws IOException {
// 接收参数
int status = 1;
String companyName = "华为";
String brandName = "华为";
// 处理参数
companyName = "%" + companyName + "%";
brandName = "%" + brandName + "%";
//
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//
SqlSession sqlSession = sqlSessionFactory.openSession();
//
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 执行方法
// 1. 接口方法参数使用 @Param 方式调用
/*List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName);*/
// 2. 接口方法参数是 实体类对象 方式调用的方法
/*Brand brand = new Brand();
brand.setStatus(status);
brand.setCompanyName(companyName);
brand.setBrandName(companyName);
List<Brand> brands = brandMapper.selectByCondition(brand);*/
// 3. 接口方法参数是 map集合对象 方式调用的方法
Map map = new HashMap();
map.put("status",status);
map.put("companyName",companyName);
map.put("brandName",brandName);
List<Brand> brands = brandMapper.selectByCondition(map);
System.out.println(brands);
//
sqlSession.close();
}
测试结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZDiYBNb2-1663774584856)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829090104534.png)]
4. 动态SQL
当用户在输入条件时没有填写全部,则此时的SQL也会有所不同
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PKKwE0tI-1663774584857)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829130157249.png)]
Mybatis对动态SQL有以下标签可用
- if
- choose(when, otherwise)
- trim(where, set)
- foreach
-
if 标签 : 条件判断
- test 属性 : 逻辑表达式
<!-- 多条件查询 --> <select id="selectByCondition" resultMap="brandResultMap"> select * from tb_brand where <if test="status != null"> 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>
SQL语句会根据传递的参数值进行动态拼接。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GboUTkfh-1663774584858)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829131942496.png)]
-
where 标签
- 作用:
- 替换 where 关键字
- 回动态的去掉第一个条件前的 and
- 若所有参数没有则不加 where 关键字
<!-- 多条件查询 --> <select id="selectByCondition" resultMap="brandResultMap"> select * from tb_brand <where> <if test="status != null"> 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>
- 作用:
4.1.5 单个条件(动态SQL)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p4jRtJ5P-1663774584858)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829132625284.png)]
使用 **choose(when, otherwise)
**标签实现。choose 标签类似于 Java 中的 switch 语句
1. 接口方法
/**
* 单条件动态查询
* @param brand
* @return List<Brand>
* */
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 != '' ">
and company_name like #{companyName}
</when>
<when test="brandName != null and brandName != '' ">
and brand_name like #{brandName}
</when>
</choose>
</where>
</select>
3. 测试方法
/*
* 单条件查询
* */
@Test
public void testSelectByConditionSingle() throws IOException {
// 接收参数
int status = 1;
String companyName = "华为";
String brandName = "华为";
// 处理参数
companyName = "%" + companyName + "%";
brandName = "%" + brandName + "%";
//
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//
SqlSession sqlSession = sqlSessionFactory.openSession();
//
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 执行方法
Brand brand = new Brand();
// brand.setStatus(status);
brand.setCompanyName(companyName);
// brand.setBrandName(companyName);
List<Brand> brands = brandMapper.selectByConditionSingle(brand);
System.out.println(brands);
//
sqlSession.close();
}
测试结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g9oXVLMW-1663774584860)(C:\Users\18517\AppData\Roaming\Typora\typora-user-images\image-20220829151356029.png)]