2. Mybatis 完成增删改查

1. 任务描述

请添加图片描述

如上图所示产品原型,里面包含了品牌数据的 查询按条件查询添加删除批量删除修改 等功能,而这些功能其实就是对数据库表中的数据进行 CRUD 操作。接下来就使用 Mybatis 完成品牌数据的增删改查操作。以下是要完成的功能列表:

  • 查询
    查询所有数据
    查看详情
    条件查询

  • 添加

  • 修改
    修改全部字段
    修改动态字段

  • 删除
    删除一个
    批量删除

2. 准备工作

(1) 创建数据库表 tb_brand

-- 删除tb_brand表
drop table if exists 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);

SELECT * FROM tb_brand;

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

    public Integer getId() {
        return id;
    }
    //getter、setter方法
    //toString方法
}

(3) 创建测试用例 MybatisTest

在这里插入图片描述

public class MybatisTest {
}

(4) 安装 MyBatisX 插件

在此之前,UserMapper 接口和对应的 UserMapper.xml 文件都是手写的,安装 MyBatisX 插件后,可以根据 UserMapper 接口中的方法自动地向 UserMapper.xml 文件中添加 statement。

MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。

主要功能:
① XML 和接口方法相互跳转
② 根据接口方法生成 statement

安装完 mybatisx 插件后,可以点击代码前面的小鸟实现 “XML 和接口方法相互跳转”;也可以根据在 mapper 接口中写的接口方法生成 statement。

在这里插入图片描述

UserMapper.xml 中的生成结果如下:

<!--statement-->
<select id="selectById" resultType="com.itheima.pojo.User"></select> 

再向其中添加 SQL 语句即可。

<!--statement-->
<!--改一下别名-->
<select id="selectById" resultType="user">
    select * from tb_user where id=#{id};
</select>

3. 配置文件完成查询功能

今后无论用 mybatis 完成多么复杂的功能,基本就三步:

  • 在 Mapper 接口中编写接口方法
    参数:无
    返回类型:List<Brand>
  • 利用接口方法生成 SQL 映射文件中的 statement,并补充 SQL 语句
  • 执行方法,测试

在三步之前,首先配置好 pom.xml 文件(同前),准备好 logback.xml(同前),创建实体类 Brand(同前),准备好核心配置文件 mybatis-config.xml 如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--相当于给pojo下面的所有实体类都取了别名
    别名默认是类名,不区分大小写,可以不用带所在包的名称-->
    <typeAliases>
        <package name="com.itheima.pojo"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/><!--该操作可以被spring接管-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--mybatis:数据库名-->
                <!--jdbc:mysql:///mybatis?useSSL=false"也可以-->
                <property name="url" value="jdbc:mysql://localhost/mybatis?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--更改sql映射文件路径-->
        <!--注意:resource下新建的是dictionary,
        分隔符用“/”,不能用“.”-->
        <!--<mapper resource="com/itheima/mapper/UserMapper.xml"/>-->
        <!--用包扫描的方式来加载 SQL 映射文件-->
        <!--通过接口来找sql映射文件,所以路径中的分隔符用"."-->
        <package name="com.itheima.mapper"/>
    </mappers>
</configuration>

3.1 查询所有数据

下面开始三个基本步骤:

(1) 编写 Mapper 接口

public interface BrandMapper {
    List<Brand> selectAll();
}

(2) SQL 映射文件:由 Mapper 接口方法生成 statement,并补充编写 SQL 语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.BrandMapper">
	<!--statement-->
	<!--生成后改一下别名-->
    <select id="selectAll" resultType="brand">
        select * from tb_brand;
    </select>
</mapper>

(3) 编写测试代码

public class MybatisTest {
    @Test
    public void testSelectAll() throws IOException {
        //加载mybatis核心配置文件,获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象,用它来执行SQL
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取UserMapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
        //执行方法
        List<Brand> brands = brandMapper.selectAll();
        System.out.println(brands);
        //释放资源
        sqlSession.close();
    }
}

点这里可以执行测试代码:

在这里插入图片描述
输出结果:

在这里插入图片描述

在输出结果中可以看出,有些字段为 null,这是因为数据库表中的字段名称与实体类的属性写法不同,对应不上:

在这里插入图片描述

解决方案:

(1) 起别名:对不一样的列名起别名,让别名和实体类的属性名相同。

<select id="selectAll" resultType="brand">

	select id,brand_name as brandName, company_name as companyName, ordered, description
	from tb_brand;
</select>

缺点:每次查询都要定义一次别名。

(2) SQL 片段

<!--SQL片段-->
<sql id="brand_column">
	<!--起别名时,as可以省略-->
    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>

缺点:如果 select 语句所要查询的字段各不相同,就要定义各种各样的 SQL 片段,不灵活。

(3) resultMap最常用

<!--resultMap的id随便写-->
<!--type就是原SQL语句外部标签的resulType属性值-->
<resultMap id="brandResultMap" type="brand">
    <!--把数据库表字段与实体类属性写法不同的写在这里-->
    <result column="brand_name" property="brandName"/>
    <result column="company_name" property="companyName"/>
</resultMap>
<!--resultType属性改成resultMap属性-->
<select id="selectAll" resultMap="brandResultMap">
    select * from tb_brand;
</select>

在这里插入图片描述

3.2 查看详情

在这里插入图片描述
有些数据的属性比较多,在页面表格中无法全部实现,而只会显示部分,而其他属性数据的查询可以通过 查看详情 来进行查询,如上图所示。

查看详情就是根据 id 查询数据。

在 BrandMapper 接口中添加:

Brand selectById(int id);

在 BrandMapper.xml 中添加:

<select id="selectById" parameterType="int" resultMap="brandResultMap">
	# “#{id}”一般与接口方法的形参名称一致
    select * from tb_brand where id=#{id}; 
</select>

参数占位符
① #{}:会被替换为 “?”,防止 SQL 注入(更好)
② ${}:拼接 SQL,一定会存在 SQL 注入问题
适用情况:一般的参数传递用 #{};表名或列名不固定时用 ${}

在这里插入图片描述

参数类型:parameterType="int"可省略,Integer 也可。

特殊字符:如小于号 “<” 不能直接出现,解决方法有:

① 转义字符

<select id="selectById" resultMap="brandResultMap">
    select * from tb_brand where id &lt; #{id}; 
</select>

② CDATA 区

<select id="selectById" resultMap="brandResultMap">
    select * from tb_brand where id
    # 大写CD+enter
    <![CDATA[
        <
    ]]>
    #{id};
</select>

在测试用例 MybatisTest.java 中添加:

@Test
public void testSelectById() throws IOException {
    //接收参数
    int id = 1;
    //加载mybatis核心配置文件,获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //获取SqlSession对象,用它来执行SQL
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //获取UserMapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //执行方法
    Brand brand = brandMapper.selectById(id);
    System.out.println(brand);
    //释放资源
    sqlSession.close();
}

3.3 条件查询

在这里插入图片描述

上图功能为 “进行多条件查询,将查询结果展示在下方的表格中”。

分析: 条件字段 企业名称品牌名称 需要进行模糊查询,所以条件应该是:
在这里插入图片描述

(1) 编写接口方法

当查询条件不只一个时,就需要考虑接口方法形参与 SQL 语句占位符的对应问题,解决方法有三种:

散装参数@Param(“SQL参数占位符名称”)表示把该参数传给哪个占位符。

List<Brand> selectByCondition(
		//status参数传给叫“status”的占位符
        @Param("status") int status,
        @Param("companyName") String companyName,
        @Param("brandName") String brandName);

对象参数:把查询条件封装成实体类的对象传递到接口方法中,使 SQL 语句根据对象的 getter 方法获取对应属性。条件是占位符名称要与实体类的属性名称一致。

List<Brand> selectByCondition(Brand brand);

Map 集合参数:也可以把查询条件封装成 Map 集合,Map 集合键的名称要与 SQL 语句中的占位符名称一致。

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+"%";
    //加载mybatis核心配置文件,获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //获取SqlSession对象,用它来执行SQL
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //获取UserMapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //执行方法
    List<Brand> brands = brandMapper.selectByCondition(status,companyName,brandName);
    System.out.println(brands);
    //释放资源
    sqlSession.close();
}

对象参数的测试

@Test
public void testSelectByCondition() throws IOException {
    //接收参数
    int status = 1;
    String companyName = "小米";
    String brandName = "小米";
    //模糊查询,所以要处理参数
    companyName = "%"+companyName+"%";
    brandName = "%"+brandName+"%";
    //封装对象
    Brand brand = new Brand();
    brand.setStatus(1);
    brand.setCompanyName(companyName);
    brand.setBrandName(brandName);
    //加载mybatis核心配置文件,获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //获取SqlSession对象,用它来执行SQL
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //获取UserMapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //执行方法(传递对象参数)
    List<Brand> brands = brandMapper.selectByCondition(brand);
    System.out.println(brands);
    //释放资源
    sqlSession.close();
}

③ Map 集合的测试

@Test
public void testSelectByCondition() throws IOException {
    //接收参数
    int status = 1;
    String companyName = "小米";
    String brandName = "小米";
    //模糊查询,所以要处理参数
    companyName = "%"+companyName+"%";
    brandName = "%"+brandName+"%";
    //封装对象
    Map map = new HashMap();
    map.put("status", status);
    map.put("companyName",companyName);
    map.put("brandName",brandName);
    //加载mybatis核心配置文件,获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //获取SqlSession对象,用它来执行SQL
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //获取UserMapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //执行方法(传递对象参数)
    List<Brand> brands = brandMapper.selectByCondition(map);
    System.out.println(brands);
    //释放资源
    sqlSession.close();
}

输出结果:

在这里插入图片描述

3.4 动态条件查询

3.4.1 动态条件查询之多条件

上节的条件查询存在一个 bug。用户在输入条件时,可能不会填写所有的条件,这时就查询不出来,所以 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}

SQL 语句会随着用户的输入或外部条件的变化而变化,称为动态 SQL,Mybatis 对动态 SQL 有很强大的支撑:

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

下面先来学习 if 标签和 where 标签:

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>
//封装对象
Map map = new HashMap();
map.put("status", status);
map.put("companyName",companyName);
// map.put("brandName",brandName);

输出结果:

在这里插入图片描述

但是它也存在问题,如果此时给的参数值是:

Map map = new HashMap();
// map.put("status" , status);
map.put("companyName", companyName);
map.put("brandName" , brandName);

拼接的 SQL 语句就变成了:

select * from tb_brand 
where and company_name like ? and brand_name like ?

上面的语句中 where 后直接跟 and,是错误的 SQL 语句,解决方式有两种(推荐第二种):

(1) 恒等式:如添加 ”1=1“

在这里插入图片描述

在这里插入图片描述

(2) 用 where 标签替换 where 关键字:在 SQL 语句中替换 where 关键字,动态去掉第一个条件前的 and,如果所有的参数没有值则不加 where 关键字(推荐)。

在这里插入图片描述

在这里插入图片描述

3.4.2 动态条件查询之单条件

在这里插入图片描述

如上图所示,在查询时只能选择 品牌名称当前状态企业名称 这三个条件中的一个,但是用户选哪一个不能确定。这种就属于单个条件的动态 SQL 语句。

这种需求需要使用到 choose(when, otherwise) 标签实现,类似于 Java 中的 switch-case-default 语句。

(1) 编写接口方法

List<Brand> selectByConditionSingle(Brand brand);

(2) 编写SQL语句

方式 1(不常用)

<select id="selectByConditionSingle" resultMap="brandResultMap">
    select *
    from tb_brand
    where
    <choose>
        <when test="status != null">
            status = #{status}
        </when>
        <when test="companyName != null and companyName != '' ">
            company_name like #{companyName}
        </when>
        <when test="brandName != null and brandName != '' ">
            brand_name like #{brandName}
        </when>
        <otherwise>
            <!--以防所有字段都没有值时,where后面没有语句导致语法错误-->
            1=1
        </otherwise>
    </choose>
</select>

方式 2(常用):

<select id="selectByConditionSingle" resultMap="brandResultMap">
    select *
    from tb_brand
    <where>
    	<!--如果所有字段都没有值,
    	where标签就不添加where关键字-->
        <choose>
            <when test="status != null">
                status = #{status}
            </when>
            <when test="companyName != null and companyName != '' ">
                company_name like #{companyName}
            </when>
            <when test="brandName != null and brandName != '' ">
                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+"%";
    //封装对象(实体类对象或Map对象都可)
    Brand brand = new Brand();
    // brand.setStatus(status);
    brand.setCompanyName(companyName);
    // brand.setBrandName(brandName);
    
    //加载mybatis核心配置文件,获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //获取SqlSession对象,用它来执行SQL
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //获取UserMapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //执行方法(传递对象参数)
    List<Brand> brands = brandMapper.selectByConditionSingle(brand);
    System.out.println(brands);
    //释放资源
    sqlSession.close();
}

4. 配置文件完成添加功能

4.1 添加数据

在这里插入图片描述

上图是添加数据的页面,在该页面输入想要的数据后点击 ”提交“ 按钮,就会将这些数据添加到数据库中。接下来就来实现添加数据的操作。

(1) 编写 Mapper 接口方法

参数:除了 id 之外的所有数据(id会自增)
结果:void

void add(Brand brand);

(2) 编写SQL语句:SQL 映射文件

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

(3) 测试

注意:插入数据要提交事务

@Test
public void testAdd() throws IOException {
    //接收参数
    int status = 1;
    String companyName = "波导";
    String brandName = "波导手机";
    String description = "手机中的战斗机";
    int ordered = 10;
    //封装对象
    Brand brand = new Brand();
    brand.setStatus(status);
    brand.setCompanyName(companyName);
    brand.setBrandName(brandName);
    brand.setDescription(description);
    brand.setOrdered(ordered);
    //加载mybatis核心配置文件,获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //获取SqlSession对象,用它来执行SQL
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //获取UserMapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //执行方法(传递对象参数)
    brandMapper.add(brand);
    //手动提交事务
    sqlSession.commit();
    //释放资源
    sqlSession.close();
}

在上面的测试代码中,提交事务是必须的,否则事务回滚。虽 SQL 执行成功,但数据库表中未插入数据。

在这里插入图片描述

还有一种自动提交事务的方式:

SqlSession sqlSession = sqlSessionFactory.openSession(true);
  • openSession():默认开启事务,进行增删改操作后需要使用 sqlSession.commit();手动提交事务
  • openSession(true):可以设置为自动提交事务(关闭事务)

4.2 添加完数据后返回主键

数据添加成功后,要想获取数据的 id,要在 insert 标签上添加两个属性:

  • useGeneratedKeys:获取自增长的主键值。true 表示获取。
  • keyProperty :将获取到的主键值封装到哪个属性

在这里插入图片描述

就能在插入数据后获取到 id:

brandMapper.add(brand);
System.out.println(brand.getId());

5. 配置文件完成修改功能

5.1 修改全部字段

在这里插入图片描述

如图所示是修改页面,用户在该页面编辑需要修改的数据,点击 “提交” 按钮,就会修改数据库中对应的数据。

接下来我们就具体来实现:

(1) 编写 Mapper 接口方法
参数:所有数据
结果:void

void update(Brand brand);

(2) 编写SQL语句:SQL映射文件

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

(3) 测试方法

@Test
public void testUpdate() throws IOException {
    //接收参数
    int status = 1;
    String companyName = "波导";
    String brandName = "波导手机";
    String description = "波导手机,手机中的战斗机";
    int ordered = 200;
    int id = 7;
    //封装对象
    Brand brand = new Brand();
    brand.setStatus(status);
    brand.setCompanyName(companyName);
    brand.setBrandName(brandName);
    brand.setDescription(description);
    brand.setOrdered(ordered);
    brand.setId(id);
    //加载mybatis核心配置文件,获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //获取SqlSession对象,用它来执行SQL
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    //获取UserMapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //执行方法(传递对象参数)
    brandMapper.update(brand);
    //提交事务
    sqlSession.commit();
    //释放资源
    sqlSession.close();
}

5.2 修改动态字段

在上节,修改信息时修改的是所有的字段。如果用户修改信息时,有的输入框没有输入内容,就会导致修改后有的字段为空。

这显然不合理,未输入的内容应该保留之前的数据。这就需要用到动态 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 标签而不是 set 关键字的原因:
① 若最后一个字段未修改,set 语句最后就是逗号,语法错误。
② 若所有字段都未修改,set 语句就空留一个 set,语法错误。

测试:

@Test
public void testUpdate() throws IOException {
    //接收参数
    int status = 0;
    String companyName = "波导";
    String brandName = "波导手机";
    String description = "波导手机,手机中的战斗机";
    int ordered = 200;
    int id = 7;
    //封装对象
    Brand brand = new Brand();
    brand.setStatus(status);
    // brand.setCompanyName(companyName);
    // brand.setBrandName(brandName);
    // brand.setDescription(description);
    // brand.setOrdered(ordered);
    brand.setId(id);
    //加载mybatis核心配置文件,获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //获取SqlSession对象,用它来执行SQL
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    //获取UserMapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //执行方法(传递对象参数)
    brandMapper.update(brand);
    //提交事务
    sqlSession.commit();
    //释放资源
    sqlSession.close();
}

6. 配置文件完成删除功能

6.1 删除单条数据

在这里插入图片描述

如上图所示,每行数据后面都有一个 删除 按钮,当用户点击该按钮时,就会将该行数据删掉。

这种删除是通过主键 id 删除的,因为 id 是表中数据的唯一标识。

接下来就来实现该功能。

(1) 编写 Mapper 接口方法

void deleteById(int id);

(2) 编写 SQL

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

(3) 测试

public void testDeleteById() throws IOException {
    //接收参数
    int id = 7;
    //加载mybatis核心配置文件,获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //获取SqlSession对象,用它来执行SQL
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    //获取UserMapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //执行方法(传递对象参数)
    brandMapper.deleteById(id);
    //提交事务
    sqlSession.commit();
    //释放资源
    sqlSession.close();
}

6.2 批量删除数据

在这里插入图片描述

如上图所示,用户可以选择多条数据,然后点击上面的 删除 按钮,就会删除数据库中对应的多行数据。

选中复选框并批量删除时,会将所有被选中记录的 id 封装成一个数组,再遍历数组,根据数组中的每个 id 来删除对应的记录。

(1) 编写 Mapper 接口方法
参数:id数组
结果:void

void deleteByIds(int[] ids);

(2) 编写 SQL

方法 1:

<delete id="deleteByIds">
	#缺点:几个”?“不确定 
    delete from tb_brand
    where id in (?.?.?)
</delete>

方法 2:

foreach 标签:用来迭代任何可迭代的对象(如数组,集合)。

  • collection 属性:mybatis 会将数组参数,封装为一个 Map 集合。
    默认:array = 数组
    使用@Param注解改变map集合的默认key的名称
  • 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>

如果 Mapper 接口方法加上@Param("ids") 注解,foreach 的 collection 属性值就能写成 “ids”,从而保持与 id 数组名一致。

void deleteByIds(@Param("ids") int[] ids);
<delete id="deleteByIds">
    delete from tb_brand where id
    in
    <foreach collection="ids" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
</delete>

假如数组中的 id 数组是 {1,2,3},拼接后的 SQL 语句就是delete from tb_brand where id in (1,2,3)

(3) 测试

@Test
public void testDeleteByIds() throws IOException {
    //接收参数
    int[] ids = {2,3};
    //加载mybatis核心配置文件,获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //获取SqlSession对象,用它来执行SQL
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    //获取UserMapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //执行方法(传递对象参数)
    brandMapper.deleteByIds(ids);
    //提交事务
    sqlSession.commit();
    //释放资源
    sqlSession.close();
}

7. mybatis 参数传递

Mybatis 接口方法中可以接收各种各样的参数,如下:

  • 多个参数
  • 单个参数,可以是如下类型:
    • POJO 类型(实体类,如 User、Brand)
    • Map 集合类型
    • Collection 集合类型
    • List 集合类型
    • Array 类型
    • 其他类型

7.1 多个参数

如下面的代码,就是接收两个参数,而接收多个参数的一种方式是使用 @Param 注解。

在这里插入图片描述

那么为什么要加该注解呢?这个问题要弄明白就必须来研究Mybatis 底层对于这些参数是如何处理的。

接口方法中定义多个参数时,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);

所以,代码可以这么写:

在这里插入图片描述
上面的写法,代码的可读性会变差,此时可以使用 @Param 注解。

在 username 参数前加上 @Param 注解:

User select(@Param("username") String username, String password);

Mybatis 在封装 Map 集合时,键名就会变成如下:

map.put("username", 参数值1);//原来是arg0
map.put("param1", 参数值1);
map.put("arg1", 参数值2);
map.put("param2", 参数值2);

所以代码可以这么写:

在这里插入图片描述

结论:以后接口参数是多个时,在每个参数上都使用 @Param 注解。这样代码的可读性更高。

7.2 单个参数

(1) POJO 类型(实体类,如 User、Brand)
直接使用。要求 属性名参数占位符 名称一致。

(2) Map 集合类型
直接使用。要求 map集合的 键名参数占位符名称一致。

(3) Collection 集合类型
Mybatis 会将集合封装到 map 集合中,如下:

map.put("arg0", collection集合);
map.put("collection", collection集合);

可以使用 @Param 注解替换 map 集合中默认的 arg 键名。

(4) List 集合类型
Mybatis 会将集合封装到 map 集合中,如下:

map.put("arg0",list集合);
map.put("collection",list集合);
map.put("list",list集合);

可以使用 @Param 注解替换 map 集合中默认的 arg 键名。

(5) Array 类型
Mybatis 会将集合封装到 map 集合中,如下:

map.put("arg0",数组);
map.put("array",数组);

可以使用 @Param 注解替换 map集合中默认的 arg 键名。

(6) 其他类型
比如 int 类型, 参数占位符 名称叫什么都可以,尽量做到见名知意。

8. 注解完成增删改查

使用注解开发会比配置文件开发更加方便。如下就是使用注解进行开发:

@Select(value = "select * from tb_user where id = #{id}")
public User select(int id);

注解是用来替换 SQL 映射文件的。所以,使用注解就不需要在 SQL 映射文件中书写对应的 statement。

Mybatis 针对 CURD 操作都提供了对应的注解,已经做到见名知意。如下:

  • 查询 :@Select
  • 添加 :@Insert
  • 修改 :@Update
  • 删除 :@Delete

【提示】注解完成简单功能,配置文件完成复杂功能

接下来通过一个案例来展示 Mybatis 的注解开发:

@Select("select * from tb_user where id=#{id}")
User selectById(int id);

测试:

public class MybatisDemo {
    public static void main(String[] args) throws IOException {
        //加载mybatis核心配置文件,获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象,用它来执行SQL
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取UserMapper接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectById(1);
        System.out.println(user);
        //释放资源
        sqlSession.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值