1.Mybatis实现CRUD操作
1.CRUD是什么?
CRUD:增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete)
- 查询
- 查询所有数据
- 查询详情
- 条件查询
- 添加
- 修改
- 修改全部字段
- 修改动态字段
- 删除
- 删除一个
- 批量删除
2.环境准备
数据库表(tb_brand)及数据准备
-- 创建tb_brand表
create 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:启用
status int
);
-- 添加数据
insert into tb_brand (brand_name, company_name, ordered, description, status)
values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),
('小米', '小米科技有限公司', 50, 'are you ok', 1);
实体类 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。自己写时要补全这部分代码
}
测试用例在test包下创建
安装 MyBatisX 插件
-
MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
-
主要功能
- XML映射配置文件 和 接口方法 间相互跳转
- 根据接口方法生成 statement
2.查询所有数据
1.编写接口方法
查询所有数据功能是不需要根据任何条件进行查询的,所以此方法不需要参数。
结果:List,因为查到的数据是一个表的数据,有很多列,用list集合接收
2.编写sql语句
3.编写测试方法
package com;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import org.w3c.dom.ls.LSOutput;
import pojo.Brand;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MybatisBrandTest {
@Test
public void testSelectAll() throws Exception {
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
List<Brand> brands = brandMapper.selectAll();
for (Brand brand : brands) {
System.out.println(brand);
}
//5.释放资源
sqlSession.close();
}
}
我们发现有的数据封装成功了,有的没有成功,这是为啥啊?!
这个问题可以通过两种方式进行解决:
- 给字段起别名
- 使用resultMap定义字段和属性的映射关系
1.给字段起别名
从上面结果可以看到 brandName
和 companyName
这两个属性的数据没有封装成功,查询 实体类 和 表中的字段 发现,在实体类中属性名是 brandName
和 companyName
,而表中的字段名为 brand_name
和 company_name
,如下图所示 。那么我们只需要保持这两部分的名称一致这个问题就迎刃而解。
我们可以在写sql语句时给这两个字段起别名,将别名定义成和属性名一致即可。as可以省略
<select id="selectAll" resultType="brand">
select
id, brand_name as brandName, company_name as companyName, ordered, description, status
from tb_brand;
</select>
而上面的SQL语句中的字段列表书写麻烦,如果表中还有更多的字段,同时其他的功能也需要查询这些字段时就显得我们的代码不够精炼。Mybatis提供了sql
片段可以提高sql的复用性。
将需要复用的SQL片段抽取到 sql
标签中
<sql id="brand_column">
id, brand_name as brandName, company_name as companyName, ordered, description, status
</sql>
使用 include
标签引用上述的 SQL 片段,而 refid
指定上述 SQL 片段的id值。
<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"></include>
from tb_brand
</select>
运行测试方法,我们发现所有数据都封装成功了~
2.使用resultMap解决
起别名 + sql片段的方式可以解决上述问题,但是它也存在问题。如果还有功能只需要查询部分字段,而不是查询所有字段,那么我们就需要再定义一个 SQL 片段,这就显得不是那么灵活。
<resultMap id="brandResultMap" type="brand">
<result column="brand_name" property="brandName"></result>
<result column="company_name" property="companyName"></result>
</resultMap>
<select id="selectAll" resultMap="brandResultMap">
select *from tb_brand;
</select>
注意:在上面只需要定义 字段名 和 属性名 不一样的映射,而一样的则不需要专门定义出来。
运行后同样也全部封装成功了~
3.查询详情,根据id或者其他条件查询
1.编写接口方法
2.编写sql语句
3.编写测试方法
public class MybatisBrandTest {
@Test
public void testSelectAll() throws Exception {
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法 传入id = 1;
Brand brands = brandMapper.selectById(1);
System.out.println(brands);
//5.释放资源
sqlSession.close();
}
}
执行结果:
4.parameterType使用
对于有参数的mapper接口方法,我们在映射配置文件中应该配置 ParameterType
来指定参数类型。只不过该属性都可以省略。如下图:
5.SQL语句中特殊字段处理 > <等等…
特殊字段的转义对应格式,请看这位大佬的总结:https://blog.csdn.net/qq_31832209/article/details/118520862
如果只是查询一条数据,比如一行数据那么我们在创建接口时就不用List来封装,而是直接使用实体类来封装,如下图:
如果我们最终查询到多条数据,则会报错!如图
怎么转义特殊字段从而获得指定范围的数据?
4.按条件查询(很重要)
我们经常会碰到按照自己所输入的条件来查询我们想要的东西,比如我们在网上买电脑时会输入自己想要的一些配置,然后筛选出一些符合条件的商品供自己选择
而我们做这个功能需要分析最终的SQL语句应该是什么样,思考两个问题
- 条件表达式
- 如何连接
编写接口方法
-
参数:所有查询条件
-
结果:List
-
在映射配置文件中编写SQL语句
-
编写测试方法并执行
1.编写接口方法
该功能有三个参数,我们就需要考虑定义接口时,参数应该如何定义。Mybatis针对多参数有多种实现
1.使用@Param注解接口
使用 @Param("参数名称")
标记每一个参数,在映射配置文件中就需要使用 #{参数名称}
进行占位
List<Brand>selectByCondition(@Param("status") int status,@Param("brandName") String brandName
,@Param("companyName") String companyName);
2.使用实体类封装
将多个参数封装成一个 实体对象 ,将该实体对象作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内容}
时,里面的内容必须和实体类属性名保持一致。
3.使用map集合
将多个参数封装到map集合中,将map集合作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内容}
时,里面的内容必须和map集合中键的名称一致。
2.编写sql语句
3.编写测试方法
1.使用@Param注解
String companyName = "华为";
String brandName = "华为";//全程为华为技术有限公司 但是我们可以通过模糊查询查到含有华为的数据
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法 传入id = 1;
List<Brand> brands = brandMapper.selectByCondition(brandName,companyName);
System.out.println(brands);
sqlSession.close();
2.使用实体类封装
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
Brand brand = new Brand();
brand.setBrandName("华为");
brand.setCompanyName("华为");
List<Brand> brands1 = brandMapper.selectByCondition(brand);
System.out.println(brands1);
sqlSession.close();
3.使用map集合
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
Map map = new HashMap();
map.put("brandName","华为");
map.put("companyName","华为");
List<Brand>brands = brandMapper.selectByCondition(map);
System.out.println(brands);
//5.释放资源
sqlSession.close();
4.动态sql
上述功能实现存在很大的问题。用户在输入条件时,肯定不会所有的条件都填写,这个时候我们的SQL语句就不能这样写
例如用户只输入 当前状态 时,SQL语句就是
select * from tb_brand where status = #{status}
而用户如果只输入企业名称时,SQL语句就是
select * from tb_brand where company_name like #{companName}
而用户如果输入了 当前状态
和 企业名称
时,SQL语句又不一样
select * from tb_brand where status = #{status} and company_name like #{companName}
针对上述的需要,Mybatis对动态SQL有很强大的支撑:
if 标签:条件判断
test 属性:逻辑表达式
where 标签
作用:
- 替换where关键字
- 会动态的去掉第一个条件前的 and
- 如果所有的参数没有值则不加where关键字
1.sql语句
<?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.BrandMapper">
<resultMap id="BrandResultMap" type="pojo.Brand">
<result column="brand_name" property="brandName"></result>
<result column="company_name" property="companyName"></result>
</resultMap>
<select id="selectByCondition" resultMap="BrandResultMap">
select *
from tb_brand
<where>
<if test="brandName !=null and brandName !=''">and brand_name like concat('%',#{brandName},'%')</if>
<if test="companyName != null and companyName !=''">and company_name like concat('%',#{companyName},'%')
</if>
</where>
</select>
</mapper>
2.使用实体类方法
只传入部分参数
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
Brand brand = new Brand();
brand.setBrandName("华为");
//brand.setCompanyName("华为");
List<Brand> brands1 = brandMapper.selectByCondition(brand);
System.out.println(brands1);
//5.释放资源
sqlSession.close();
3.使用map集合方法
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
Map<String,Object> map = new HashMap<String,Object>();
//map.put("brandName","华为");
map.put("companyName","华为");
List<Brand>brands = brandMapper.selectByCondition(map);
System.out.println(brands);
//5.释放资源
sqlSession.close();
5.单个条件动态sql查询
在查询时只能选择 品牌名称
、当前状态
、企业名称
这三个条件中的一个,但是用户到底选择哪儿一个,我们并不能确定。这种就属于单个条件的动态SQL语句。
这种需求需要使用到 choose(when,otherwise)标签
实现, 而 choose
标签类似于Java 中的switch语句。
1.编写接口方法 实体类和map集合方法
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>
3.编写测试方法
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法 传入id = 1;
Brand brand = new Brand();
brand.setCompanyName("华为");
List<Brand> brands = brandMapper.selectByConditionSingle(brand);
System.out.println(brands);
/* Map<String,Object> map = new HashMap<String,Object>();
map.put("companyName","华为");
List<Brand> brands1 = brandMapper.selectByConditionSingle(map);
System.out.println(brands1);*/
//5.释放资源
sqlSession.close();
结果:
6.添加数据
1.编写接口方法
public void add(Brand brand);
public void add(Map<String,Object> map);
2.编写sql语句
<?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.BrandMapper">
<resultMap id="BrandResultMap" type="pojo.Brand">
<result column="brand_name" property="brandName"></result>
<result column="company_name" property="companyName"></result>
</resultMap>
<insert id="add" useGeneratedKeys="true" keyProperty="id">
<!--useGeneratedKeys="true" keyProperty="id"开启返回主键权限,如果不开的话我们是看不到主键的-->
insert into tb_brand(brand_name, company_name, ordered, description, status)
values(#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
</mapper>
3.编写测试方法
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);//设为true是自动提交事务
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法 传入id = 1;
Brand brand = new Brand();
brand.setStatus(1);
brand.setCompanyName("小米科技有限公司");
brand.setBrandName("小米");
brand.setDescription("手机中的战斗机");
brand.setOrdered(100);
brandMapper.add(brand);
System.out.println(brand);
/*Map<String,Object> map = new HashMap<String,Object>();
map.put("brandName","黑鲨");
map.put("companyName","腾讯");
map.put("ordered",1);
map.put("description","牛啊牛");
map.put("status",1);
brandMapper.add(map);
System.out.println(map);*/
//sqlSession.commit(); 手动提交事务
//5.释放资源
sqlSession.close();
未开启返回主键结果:
开启返回主键结果:
7.修改数据
1.编写接口方法
public void update(Brand brand);
2.编写sql语句
<?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.BrandMapper">
<resultMap id="BrandResultMap" type="pojo.Brand">
<result column="brand_name" property="brandName"></result>
<result column="company_name" property="companyName"></result>
</resultMap>
<update id="update" useGeneratedKeys="true" keyProperty="id">
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="status !=null">status = #{status}</if>
<if test="description !=null and description != ''">description = #{description}</if>
</set>
where id = #{id};
</update>
<!--*set* 标签可以用于动态包含需要更新的列,忽略其它不更新的列。-->
</mapper>
3.编写测试方法
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法 传入id = 1;
Brand brand = new Brand();
//brand.setStatus(0);
//brand.setBrandName("三星Galaxy");
//brand.setCompanyName("三星科技有限公司");
brand.setDescription("手机中的???");
//brand.setOrdered(100);
brand.setId(10);
brandMapper.update(brand);
System.out.println(brand);
sqlSession.close();
8.删除某一行
1.编写接口方法
public void deleteById(Brand brand);
2.编写sql语句
<delete id="deleteById">
delete from tb_brand where id = #{id};
</delete>
3.编写测试方法
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
Brand brand = new Brand();
brand.setId(10);
brandMapper.deleteById(brand);
结果:
9.批量删除
1.编写接口方法
public void deleteByIds(int[] ids);
2.编写sql语句
<delete id="deleteByIds">
delete from tb_brand where id in <foreach collection="array" item="id" separator=","
open="(" close=")">#{id}</foreach>;
</delete>
foreach 标签
用来迭代任何可迭代的对象(如数组,集合)。
- collection 属性:
- mybatis会将数组参数,封装为一个Map集合。
- 默认:array = 数组
- 使用@Param注解改变map集合的默认key的名称
- mybatis会将数组参数,封装为一个Map集合。
- item 属性:本次迭代获取到的元素。
- separator 属性:分隔符。
foreach
标签不会错误地添加多余的分隔符。也就是最后一次迭代不会加分隔符。 - open 属性:该属性值是在拼接SQL语句之前拼接的语句,只会拼接一次
- close 属性:该属性值是在拼接SQL语句拼接后拼接的语句,只会拼接一次
3.编写测试方法
//1.加载mybatis配置文件
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
//2.获取sqlsession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//3.获取Mapper代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
Brand brand = new Brand();
int[] ids = {13, 14, 15};
brandMapper.deleteByIds(ids);
//5.释放资源
sqlSession.close();
1.结语
终终终终终终终.max 于写完了,第一次学总结起来问题太多了,还要多多努力啊,不过收货了很多知识和闭坑点,也是值得的,只要自己相信自己,总有一天我也会变得很强的!加油奥利给!!!