Mybatis实现CRUD

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.给字段起别名

从上面结果可以看到 brandNamecompanyName 这两个属性的数据没有封装成功,查询 实体类 和 表中的字段 发现,在实体类中属性名是 brandNamecompanyName ,而表中的字段名为 brand_namecompany_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的名称
  • 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 于写完了,第一次学总结起来问题太多了,还要多多努力啊,不过收货了很多知识和闭坑点,也是值得的,只要自己相信自己,总有一天我也会变得很强的!加油奥利给!!!
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小熊佩萁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值