【Mybatis】配置文件完成增删改查

MyBatis的配置参数内容可以参考配置_MyBatis中文网

目标

  1. 查询
  • 查询所有数据
  • 查看详情
  • 条件查询
  1. 添加
  2. 修改
  • 修改全部字段
  • 修改动态字段
  1. 删除
  • 删除一个
  • 批量删除

准备环境

  • 数据库表tb_brand
  • 实体类 Brand
  • 测试用例
  • 安装 MyBatisX 插件

数据库表

创建如下内容的表,并添加数据

drop table if exists tb_brand;

create table tb_brand(
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);

select * from tb_brand;

实体类Brand

创建含有如下字段的实体类Brand,getter和setter方法以及toString方法可以通过idea快捷键生成,就不写了

public class Brand {
    private int id;
    private String brandName;
    private String companyName;
    private int ordered;
    private String description;
    private int status;
}

测试用例

在测试test文件夹下创建一个测试文件

image

MybatisX插件

简介
MyBatisX是一款基于IDEA的快速开发插件,为效率而生,主要功能有:

  • xml和接口方法相互跳转
  • 根据接口方法生成statement

安装
直接在idea的plugin下搜索就可以了

查询

查询所有数据

步骤

  1. 编写接口方法:Mapper接口
  • 参数:无
  • 结果:List<Brand>
public interface BrandMapper {
    /**
     * 查询所有
     */
    List<Brand> selectAll();
}
  1. 编写sql语句:sql映射文件

这一步MyBatisX帮了很大的忙,安装插件后,在BrandMapper.java中就会出现这样一只小鸟,如果selectAll还没有对应的statement,它就会提示你给你生成一个statement(但是sql语句需要自己写)
点击这个小鸟会跳到BrandMapper.xml文件

image

查询所有,这个需求比较简单,但有需要注意的地方,如果用传统方法,实体类属性名和数据库表的字段名称其实是不一样的,因此后面查询是不会自动封装数据的,有两种可以解决的方法,这里只介绍最常用的resultMap方法:

<resultMap>标签内填写列名和实体类字段名对应的关系,如<result>标签的内容。
<resultMap>标签有属性id:用于表示这个map的名称,type:指向对应的实体类
<result>标签的属性column:表示数据库列名,property:表示实体类的属性名
接着在select标签内去掉resultType属性,而是用resultMap属性,指向对应的Map即可

<mapper namespace="com.test.mapper.BrandMapper">
<!--传统方法-->
<!--    <select id="selectAll" resultType="com.test.pojo.Brand">-->
<!--        select * from tb_brand;-->
<!--    </select>-->
    <resultMap id="brandResultMap" type="com.test.pojo.Brand">
        <result column="brand_name" property="brandName"/>
        <result column="company_name" property="companyName"/>
    </resultMap>

    <select id="selectAll" resultMap="brandResultMap">
        select * from tb_brand;
    </select>
</mapper>
  1. 执行方法,测试

大部分的内容都是一致的,到获取sqlsession这里都是可以重复使用的,具体见下面:

public class MyBatisTest {
    @Test
    public void testSelectAll() throws IOException {
        //加载mybatis的核心配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //获取sqlsessionFactory对象,执行sql
        SqlSession sqlSession = sqlSessionFactory.openSession();

        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
        List<Brand> brands = mapper.selectAll();

        System.out.println(brands);
    }
}

执行的结果是:

[Brand{id=1, brandName='三只松鼠', companyName='三只松鼠股份有限公司', ordered=5, description='好吃不上火', status=0}, Brand{id=2, brandName='华为', companyName='华为技术有限公司', ordered=100, description='华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能师姐', status=1}, Brand{id=3, brandName='小米', companyName='小米科技有限公司', ordered=50, description='are you ok', status=1}]

查看详情

需求
通过参数id,查询某一条指定的brand

步骤

  1. 编写接口方法:Mapper接口
  • 参数:id
  • 结果:Brand
  1. 编写sql语句
    <select id="selectById" resultMap="brandResultMap">
        select * from tb_brand where id=#{id};
    </select>

具体讲一下sql语句的一些细节,在mapper.xml中有这样一个占位符的用法,首先讲一下占位符。

占位符
在这个映射文件中有两种形式的占位符:#和$,两者的区别在于:

  • #:会将参数替换为?,为了防止sql注入
  • $:只是将sql进行拼接,不替换,会存在sql注入的问题

因此它们的使用场景为:参数传递的时候使用#{},而${}也不是完全没有用,也可以用在表名或列名不固定的情况,但是依然存在sql注入的可能性

指定参数类型

可以在<select>标签添加属性:parameterType,以指定传入的参数的数据类型,但是可以省略

特殊字符处理

由于是在xml文件中写sql语句,因此当遇到要查询<条件的时候,xml就会认为是某一个标签的开始,从而导致报错,为了解决这个问题,可以采用两种方式:

  1. 转移符号
  2. CDATA区
    在CDATA区中,里面的内容都会被当作纯文本
    <select id="selectById" resultMap="brandResultMap">
        select * from tb_brand where id
        <![CDATA[
            <
        ]]>
        #{id};
    </select>
  1. 执行方法,测试

条件查询

多条件查询

需求

用户可以根据状态、企业名称、品牌名称进行搜索,其中企业名称和品牌名称进行模糊搜索。

image

步骤

  1. 编写接口方法:Mapper接口
  • 参数:所有查询条件
  • 结果:List<Brand>
    在这一节中重点讲一下多条件查询的三种不同接收方式:

@Param()
采用@Param()的散装参数模式,其中@Param()中的值要和对应的占位符的值一致

List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName, @Param("brandName") String brandName);

对象参数
在接口中设置传入的参数为具体的pojo实体类,注意对象的属性名称参数占位符名称一致。这里的pojo类需要在代码内封装后传入。

List<Brand> selectByCondition(Brand brand);
  1. 编写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>
  1. 执行方法,测试
    这里的写测试方法和前面的大差不差,主要是由于这里需要模糊查询,在sql映射文件中并没有办法知道具体的模糊查询语句是什么,因此需要在接收参数之后对参数进行处理,如这里的需求是包含有"华为"的内容都要查询,因此在companyNamebrandName的前后都加上%
public class MyBatisTest {
    @Test
    public void testSelectAll() throws IOException {
        //接收参数
        int status = 1;
        String companyName = "华为";
        String brandName = "华为";
        //处理参数,由于是模糊查询,需要加上%
        companyName = "%" + companyName + "%";
        brandName = "%" + brandName + "%";
		
        //采用对象参数,需要将参数封装进对象内,对象参数方式
        Brand b = new Brand();
        b.setStatus(status);
        b.setCompanyName(companyName);
        b.setBrandName(brandName);
        //采用map集合,只要保证sql的占位符名称和map的key对应上即可
        Map map = new HashMap();
        map.put("status", status);
        map.put("companyName", companyName);
        map.put("brandName", brandName);

        //加载mybatis的核心配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //获取sqlsessionFactory对象,执行sql
        SqlSession sqlSession = sqlSessionFactory.openSession();

        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
        List<Brand> brands=mapper.selectByCondition(status,companyName,brandName);//@Param()方式
        List<Brand> brands=mapper.selectByCondition(b);//对象参数方式
        List<Brand> brands = mapper.selectByCondition(map);//map集合方式

        System.out.println(brands);
    }
}

动态条件查询

需求:由于用户查询的时候不一定会用上所有的条件,所以需要动态条件查询,这就需要sql语句根据用户的输入或者外部条件的变化而变化,这被称为动态sql

其他的可以参考动态SQL_MyBatis中文网

动态sql需要在sql映射中添加if条件标签,然后在test后面接逻辑表达式。但是直接像下面这种写法,如果没有满足第一个条件,那么sql语句where后面就会以and company_name开始,导致sql语句错误。

    <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>

为了满足语法要求,可以做如下改变:

  1. 在where语句后添加 1=1 恒等式
  2. 将and放到每一个条件之前

如下图所示:

image

代码为:

    <select id="selectByCondition" resultMap="brandResultMap">
        select *
        from tb_brand
        where 1=1
        <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>

然而在MyBatis中还有一个标签<where>可以便捷地解决上面这个问题,在MyBatis中文网中有如下描述:

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

image

单条件查询

用一个<choose>里面嵌套多个<when>来进行单条件查询,如果符合when当中的其中一个就执行,但是需要防止一种情况,如果没有一个条件符合的话,就会报错,因此需要写一个otherwise,当没有一个条件符合,就会执行otherwise的东西

image

添加

步骤

  1. 编写接口方法:Mapper接口
  • 参数:除了id之外的所有数据
  • 结果:void
  1. 编写sql语句:sql映射文件
  2. 执行方法,测试

1.编写接口方法

根据要求编写如下接口方法:

void add(Brand brand);

2.编写sql语句

<insert id="add">
        insert into tb_brand(brand_name,company_name,ordered,description,status)
        values (#{brandName},#{companyName},#{ordered},#{description},#{status});
    </insert>

执行方法,测试

测试方法和前面基本一样,但是注意如果不设置sqlSessionFactory.openSession()的参数为true,则需要在后面手动提交事务,否则无法更新到数据库里。

public class MyBatisTest {
    @Test
    public void testAdd() throws IOException {
        //接收参数
        int status = 1;
        String companyName = "波导手机";
        String brandName = "波导";
        String description = "手机中的战斗机";
        int ordered = 100;
        //采用对象参数,需要将参数封装进对象内
        Brand b = new Brand();
        b.setStatus(status);
        b.setBrandName(brandName);
        b.setCompanyName(companyName);
        b.setDescription(description);
        b.setOrdered(ordered);

        //加载mybatis的核心配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //获取sqlsessionFactory对象,执行sql
        SqlSession sqlSession = sqlSessionFactory.openSession();//传入参数true就代表自动提交事务

        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
        mapper.add(b);

        //提交事务,否则不会加入到数据库中
        sqlSession.commit();

        //释放资源
        sqlSession.close();
    }
}

主键返回

主键返回是指在数据添加成功后,需要获取插入数据库的主键的值,比如:添加订单和订单项,并返回订单id
在insert标签里填写这两个属性,就可以绑定id,当插入成功后返回id。

useGeneratedKeys="true" keyProperty="id"

修改

修改全部字段

  1. 编写接口方法:Mapper接口
  • 参数:除了id之外的所有数据
  • 结果:void
  1. 编写sql语句:sql映射文件
  2. 执行方法,测试

编写接口方法

int update(Brand brand);//返回影响的行数

编写sql语句

    <update id="update">
        update tb_brand
        set brand_name=#{brandName},
            company_name=#{companyName},
            ordered=#{ordered},
            description=#{description},
            status=#{status}
        where id=#{id};
    </update>

修改动态字段

  1. 编写接口方法:Mapper接口
  • 参数:部分数据,封装到对象中
  • 结果:void
  1. 编写sql语句:sql映射文件
  2. 执行方法,测试

编写sql语句

使用<set><if>标签嵌套。
这里有个问题:如果封装进来的内容不包含数字部分,数字部分就会被置为0。可能需要设置默认值?

    <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>

删除

删除一个

编写接口方法

void deleteById(int id);

编写sql语句

    <delete id="deleteById">
        delete from tb_brand where id=#{id};
    </delete>

批量删除

编写接口方法

这里和前面不一样的地方是,接受的参数是一个数组

void deleteByIds(@Param("ids")int[]ids);

编写sql语句:sql映射文件

    <delete id="deleteByIds">
        delete from tb_brand
        where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>

通过标签<foreach>可以用来遍历传入的数组的元素,其中collection代表要遍历的集合,item是集合元素的代称。separator是分隔符,因为不加分隔符,foreach就会生成多个#{id},没有用逗号间隔开。open是遍历开始之前添加的符号,close是遍历结束后添加的符号。

posted @ 2022-05-15 22:17  ShaunY  阅读(77)  评论(0编辑  收藏  举报