当前位置: 首页 > news >正文

02-MyBatis查询-

文章目录

  • Mybatis CRUD练习
    • 1,配置文件实现CRUD
      • 1.1 环境准备
        • Debug01: 别名mybatisx报错
      • 1.2 查询所有数据
        • 1.2.1 编写接口方法
        • 1.2.2 编写SQL语句
        • 1.2.3 编写测试方法
        • 1.2.4 起别名解决上述问题
        • 1.2.5 使用resultMap解决上述问题
        • 1.2.6 小结
      • 1.3 查询详情
        • 1.3.1 编写接口方法
        • 1.3.2 编写SQL语句
        • 1.3.3 编写测试方法
        • 1.3.4 参数占位符
        • 1.3.5 parameterType使用
        • 1.3.6 SQL语句中特殊字段处理
        • 小结:
      • 1.4 多条件查询 ★(参数接收方式)
        • 1.4.1 编写接口方法
        • 1.4.2 编写SQL语句
        • 1.4.3 编写测试方法
          • 小结
        • 1.4.4 动态SQL ★
      • 1.5 单个条件(动态SQL)
        • 1.5.1 编写接口方法
        • 1.5.2 编写SQL语句
        • 1.5.3 编写测试方法
      • -----------------------Mybatis配置文件增删改---------------------------
      • 1.6 添加数据
        • 1.6.1 编写接口方法
        • 1.6.2 编写SQL语句
        • 1.6.3 编写测试方法
        • 1.6.4 添加-主键返回
      • 1.7 修改
        • 1.7.1 编写接口方法
        • --------修改全部字段--------
        • 1.7.2 编写SQL语句
        • 1.7.3 编写测试方法
        • --------动态修改部分字段--------
        • 1.7.2 编写SQL语句
        • 1.7.3 编写测试方法
      • 1.8 删除一行数据
        • 1.8.1 编写接口方法
        • 1.8.2 编写SQL语句
        • 1.8.3 编写测试方法
      • 1.9 批量删除
        • 1.9.1 编写接口方法
        • 1.9.2 编写SQL语句 (foreach 标签)
        • 1.9.3 编写测试方法

Mybatis CRUD练习

目标

  • 能够使用映射配置文件实现CRUD操作
  • 能够使用注解实现CRUD操作

在这里插入图片描述

1,配置文件实现CRUD

在这里插入图片描述

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

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

我们先将必要的环境准备一下。

1.1 环境准备

完全继承上面的环境,接着做

  • 数据库表(tb_brand)及数据准备

    -- mybatis数据库下
    use mybatis;
    -- 删除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);
    
  • 实体类 Brand

    cn.whu.pojo 包下创建 Brand 实体类。
    这里体会到 自动导包真的太爽了

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class Brand {// id 主键private Integer id;// 品牌名称private String brandName;// 企业名称private String companyName;// 排序字段private Integer ordered;// 描述信息private String description;// 状态:0:禁用  1:启用private Integer status;
    }
    
  • 编写测试用例

    测试代码需要在 test/java 目录下创建包及测试用例。项目结构如下:

    在这里插入图片描述

  • 安装 MyBatisX 插件

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

    • 主要功能

      • XML映射配置文件 和 接口方法 间相互跳转
      • 根据接口方法生成 statement (就是sql映射配置)
    • 安装方式

      点击 file ,选择 settings ,就能看到如下图所示界面

    在这里插入图片描述

    注意:旧版本安装完毕后可能需要重启IDEA 新版IDEA不需要

    • 插件效果

    在这里插入图片描述

    红色头绳的表示映射配置文件,蓝色头绳的表示mapper接口。在mapper接口点击红色头绳的小鸟图标会自动跳转到对应的映射配置文件,在映射配置文件中点击蓝色头绳的小鸟图标会自动跳转到对应的mapper接口。也可以在mapper接口中定义方法,自动生成映射配置文件中的 statement ,如图所示
    在这里插入图片描述
    在这里插入图片描述

Debug01: 别名mybatisx报错

问题: mybatisx插件自动生成的statement配置,resultType默认是全路径名,并未使用别名,如果强制使用别名会报错,单并不影响运行,就是看着烦
解决: 直接alter+enter -> disabled ins… 忽略掉即可 不影响程序运行的

1.2 查询所有数据

在这里插入图片描述

如上图所示就页面上展示的数据,而这些数据需要从数据库进行查询。接下来我们就来讲查询所有数据功能,而实现该功能我们分以下步骤进行实现:

  • 编写接口方法:Mapper接口

    • 参数:无

      查询所有数据功能是不需要根据任何条件进行查询的,所以此方法不需要参数。

      在这里插入图片描述

    • 结果:List

      我们会将查询出来的每一条数据封装成一个 Brand 对象,而多条数据封装多个 Brand 对象,需要将这些对象封装到List集合中返回。
      在这里插入图片描述

    • 执行方法、测试

1.2.1 编写接口方法

cn.whu.mapper 包写创建名为 BrandMapper 的接口。并在该接口中定义 List<Brand> selectAll() 方法。

public interface BrandMapper {/*** 查询所有*/List<Brand> selectAll();
}

1.2.2 编写SQL语句

reources 下创建 cn/whu/mapper 目录结构,并在该目录下创建名为 BrandMapper.xml 的映射配置文件
注意刷新一下数据库连接,否则新创建的表没有代码提示

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="cn.whu.mapper.BrandMapper"><select id="selectAll" resultType="brand">select *from tb_brand;</select>
</mapper>

1.2.3 编写测试方法

MybatisTest 类中编写测试查询所有的方法
cn.whu.test.MybatisTest

@Test
public void testSelectAll() throws Exception {//1. 获取sqlSessionFactoryInputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);//2. 获取sqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//3. 获取mapper接口的代理对象BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法List<Brand> brands = mapper.selectAll();System.out.println(brands);//5. 释放资源sqlSession.close();
}

注意:现在我们感觉测试这部分代码写起来特别麻烦,我们可以先忍忍。以后我们只会写上面的第3步的代码,其他的都不需要我们来完成。

执行测试方法结果如下:

在这里插入图片描述

从上面结果我们看到了问题,有些数据封装成功了,而有些数据并没有封装成功。为什么这样呢?

这个问题可以通过两种方式进行解决:

  • 给字段起别名
  • 使用resultMap定义字段和属性的映射关系

1.2.4 起别名解决上述问题

从上面结果可以看到 brandNamecompanyName 这两个属性的数据没有封装成功,查询 实体类 和 表中的字段 发现,在实体类中属性名是 brandNamecompanyName ,而表中的字段名为 brand_namecompany_name,如下图所示 。那么我们只需要保持这两部分的名称一致这个问题就迎刃而解。

在这里插入图片描述

我们可以在写sql语句时给这两个字段起别名,将别名定义成和属性名一致即可。

<select id="selectAll" resultType="brand">selectid, brand_name as brandName, company_name as companyName, ordered, description, statusfrom tb_brand;
</select>

而上面的SQL语句中的字段列表书写麻烦,如果表中还有更多的字段,同时其他的功能也需要查询这些字段时就显得我们的代码不够精炼。Mybatis提供了sql 片段可以提高sql的复用性。

SQL片段:

  • 将需要复用的SQL片段抽取到 sql 标签中

    <sql id="brand_column">id, brand_name as brandName, company_name as companyName, ordered, description, status
    </sql>
    

    id属性值是唯一标识,引用时也是通过该值进行引用。

  • 在原sql语句中进行引用

    使用 include 标签引用上述的 SQL 片段,而 refid 指定上述 SQL 片段的id值。

    <select id="selectAll" resultType="brand">select<include refid="brand_column" />from tb_brand;
    </select>
    

最终配置:
在这里插入图片描述

1.2.5 使用resultMap解决上述问题

起别名 + sql片段的方式可以解决上述问题,但是它也存在问题。如果还有功能只需要查询部分字段,而不是查询所有字段,那么我们就需要再定义一个 SQL 片段,这就显得不是那么灵活。

那么我们也可以使用resultMap来定义字段和属性的映射关系的方式解决上述问题。

  • 在映射配置文件中使用resultMap定义 字段 和 属性 的映射关系
    <!--id: 唯一标识 随便取名  type:指的是哪个pojo的映射 支持别名--><!--<id></id> 映射主键的column: 表的列名property: 实体类的属性名<result></result> 映射其他一般字段的--><resultMap id="brandResultMap" type="brand"><result column="brand_name" property="brandName"/><result column="company_name" property="companyName"/></resultMap>

注意:在上面只需要定义 字段名 和 属性名 不一样的映射,而一样的则不需要专门定义出来

  • SQL语句正常编写
    在<select>标签中,使用resultMap属性替换 resultType属性

    <select id="selectAll" resultMap="brandResultMap">select *from tb_brand;
    </select>
    

最终BrandMapper.xml

<mapper namespace="cn.whu.mapper.BrandMapper"><resultMap id="brandResultMap" type="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.2.6 小结

实体类属性名 和 数据库表列名 不一致,不能自动封装数据

  • 起别名 : 在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样
    • 可以定义 片段,提升复用性
  • resultMap :定义 完成不一致的属性名和列名的映射

而我们最终选择使用 resultMap的方式。查询映射配置文件中查询所有的 statement 书写如下:

 <resultMap id="brandResultMap" type="brand"><!--id:完成主键字段的映射column:表的列名property:实体类的属性名result:完成一般字段的映射column:表的列名property:实体类的属性名--><result column="brand_name" property="brandName"/><result column="company_name" property="companyName"/>
</resultMap><select id="selectAll" resultMap="brandResultMap">select *from tb_brand;
</select>

1.3 查询详情

在这里插入图片描述

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

查看详情功能实现步骤:

  • 编写接口方法:Mapper接口

    在这里插入图片描述

    • 参数:id

      查看详情就是查询某一行数据,所以需要根据id进行查询。而id以后是由页面传递过来。

    • 结果:Brand

      根据id查询出来的数据只要一条,而将一条数据封装成一个Brand对象即可

  • 编写SQL语句:SQL映射文件

    在这里插入图片描述

  • 执行方法、进行测试

1.3.1 编写接口方法

BrandMapper 接口中定义根据id查询数据的方法

/*** 查看详情:根据Id查询*/
Brand selectById(int id);

1.3.2 编写SQL语句

BrandMapper.xml 映射配置文件中编写 statement,使用 resultMap 而不是使用 resultType

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

注意:上述SQL中的 #{id}先这样写,一会我们再详细讲解

1.3.3 编写测试方法

test/java 下的 cn.whu.test 包下的 MybatisTest类中 定义测试方法
cn.whu.test.MybatisTest

    @Testpublic void testSelectById() throws Exception {// 接收参数int id = 1;//1. 获取sqlSessionFactoryInputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);//2. 获取sqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//3. 获取mapper接口的代理对象BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法Brand brand = mapper.selectById(id);System.out.println(brand);//5. 释放资源sqlSession.close();}

执行测试方法结果如下:

在这里插入图片描述

1.3.4 参数占位符

查询到的结果很好理解就是id为1的这行数据。而这里我们需要看控制台显示的SQL语句,能看到使用?进行占位。说明我们在映射配置文件中的写的 #{id} 最终会被?进行占位。接下来我们就聊聊映射配置文件中的参数占位符。

mybatis提供了两种参数占位符:

  • #{} :执行SQL时,会将 #{} 占位符替换为?,将来自动设置参数值。从上述例子可以看出使用#{} 底层使用的是 PreparedStatement ★ (JDBC学了 知道了预编译 就很好理解了 )

  • ${} :拼接SQL。底层使用的是 Statement,会存在SQL注入问题。如下图将 映射配置文件中的 #{} 替换成 ${} 来看效果

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

    重新运行查看结果如下:

    在这里插入图片描述

注意 : 从上面两个例子可以看出,以后开发我们使用 #{} 参数占位符。

    * 参数占位符:1. #{}: 会将其替换为 ?, 为了防止SQL注入2. ${}: 拼sql, 会存在SQL注入问题3. 使用时机:* 参数传递的时候: #{}【 * 表名或者列名不固定的情况下: ${} 会存在SQL注入问题  】 (了解即可 基本不用)

1.3.5 parameterType使用

对于有参数的mapper接口方法,我们在映射配置文件中应该配置 ParameterType 来指定参数类型。==只不过该属性都可以省略。==如下图:

<select id="selectById" parameterType="int" resultMap="brandResultMap">select *from tb_brand where id = ${id};
</select>

parameterType=“int” 不用写了 真好。接口方法里已经有了,然后调用的时候传什么就赋什么就行了

1.3.6 SQL语句中特殊字段处理

以后肯定会在SQL语句中写一下特殊字符,比如某一个字段大于某个值,如下图

在这里插入图片描述

可以看出报错了,因为映射配置文件是xml类型的问题,而 > < 等这些字符在xml中有特殊含义,所以此时我们需要将这些符号进行转义,可以使用以下两种方式进行转义

  • 转义字符

    下图的 &lt; 就是 < 的转义字符。

    在这里插入图片描述

  • <![CDATA[内容]]> (输入大写 CD 会有代码提示)

    在这里插入图片描述

小结:

在这里插入图片描述

1.4 多条件查询 ★(参数接收方式)

在这里插入图片描述

我们经常会遇到如上图所示的多条件查询,将多条件查询的结果展示在下方的数据列表中。而我们做这个功能需要分析最终的SQL语句应该是什么样,思考两个问题

  • 条件表达式
  • 如何连接

条件字段 企业名称品牌名称 需要进行模糊查询,所以条件应该是:

在这里插入图片描述

简单的分析后,我们来看功能实现的步骤:

  • 编写接口方法

    • 参数:所有查询条件
    • 结果:List
  • 在映射配置文件中编写SQL语句

  • 编写测试方法并执行

1.4.1 编写接口方法

BrandMapper 接口中定义多条件查询的方法。

而该功能有三个参数,我们就需要考虑定义接口时,参数应该如何定义。Mybatis针对多参数有多种实现

  • 使用 @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);
    

1.4.2 编写SQL语句

BrandMapper.xml 映射配置文件中编写 statement,使用 resultMap 而不是使用 resultType

<select id="selectByCondition" resultMap="brandResultMap">select *from tb_brandwhere status = #{status}and company_name like #{companyName}and brand_name like #{brandName}
</select>

1.4.3 编写测试方法

test/java 下的 cn.whu.test 包下的 MybatisTest类中 定义测试方法
cn.whu.test.MybatisTest

  • 方式:1:散装参数

散装参数: 如果方法中有多个参数,需要使用@Param(“SQL参数占位符名称(就是#{}内的名称)”)

@Test
public void testSelectByCondition() throws Exception {// 接收参数int status = 1;String companyName = "华为";String brandName = "华为";//处理参数companyName = "%" + companyName + "%";brandName = "%" + brandName + "%";//1. 获取sqlSessionFactoryInputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);//2. 获取sqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//3. 获取mapper接口的代理对象BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法List<Brand> brands = mapper.selectByCondition(status, companyName, brandName);System.out.println(brands);//5. 释放资源sqlSession.close();
}
  • 方式2:对象参数

对象参数: 对象的属性名称要和参数占位符名称一致
(前面的test方法得注释了 否则编译不过)

@Test
public void testSelectByCondition2() throws Exception {// 接收参数int status = 1;String companyName = "华为";String brandName = "华为";//处理参数companyName = "%" + companyName + "%";brandName = "%" + brandName + "%";// 参数封装成对象Brand brand = new Brand();brand.setStatus(status);brand.setCompanyName(companyName);brand.setBrandName(brandName);//1. 获取sqlSessionFactoryInputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);//2. 获取sqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//3. 获取mapper接口的代理对象BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法List<Brand> brands = mapper.selectByCondition(brand);System.out.println(brands);//5. 释放资源sqlSession.close();
}
  • 方式3:map集合参数

map的key值映射文件sql语句里的占位符保持一致 说明: #{占位符}
在这里插入图片描述

@Test
public void testSelectByCondition3() throws Exception {// 接收参数int status = 1;String companyName = "华为";String brandName = "华为";//处理参数companyName = "%" + companyName + "%";brandName = "%" + brandName + "%";// 参数封装成对象Map map = new HashMap();//值类型是变的 所以不能有范型map.put("status",status);//key和映射sql里的占位符保持一致     说明: #{占位符}map.put("companyName",companyName);map.put("brandName",brandName);//1. 获取sqlSessionFactoryInputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);//2. 获取sqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//3. 获取mapper接口的代理对象BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法List<Brand> brands = mapper.selectByCondition(map);System.out.println(brands);//5. 释放资源sqlSession.close();
}

文件编码改成UTF-8 否则中文字符识别不了。(这样会导致日志里面出现乱码,没得办法了)
运行结果和sql语句都是偶尔们想要的

[DEBUG] 17:02:01.435 [main] c.w.m.B.selectByCondition - ==>  Preparing: select * from tb_brand where status = ? and company_name like ? and brand_name like ? 
[DEBUG] 17:02:01.454 [main] c.w.m.B.selectByCondition - ==> Parameters: 1(Integer), %华为%(String), %华为%(String) 
[DEBUG] 17:02:01.466 [main] c.w.m.B.selectByCondition - <==      Total: 1 
[Brand(id=2, brandName=华为, companyName=华为技术有限公司, ordered=100, description=华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界, status=1)]
小结

在这里插入图片描述

1.4.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}

sql语句条件是动态变化的,只写一种所有参数的呢?不行,where status = null 会导致查不出来任何值

针对上述的需要,Mybatis对动态SQL有很强大的支撑:

  • if

  • choose (when, otherwise)

  • trim (where, set)

  • foreach

我们先学习 if 标签和 where 标签:

  • if 标签:条件判断

    • test 属性:逻辑表达式
      注意:逻辑表达式里是companyName而非company_name 也就是判断传入的参数或者说占位符
    <select id="selectByCondition" resultMap="brandResultMap">select *from tb_brandwhere<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>
    

    如上的这种SQL语句就会根据传递的参数值进行动态的拼接。如果此时status和companyName有值那么就会值拼接这两个条件。

    执行结果如下:(注释掉最后一个参数)

// 参数封装成对象
Map map = new HashMap();//值类型是变的 所以不能有范型
map.put("status",status);//key和映射sql里的占位符保持一致     说明: #{占位符}
map.put("companyName",companyName);
//map.put("brandName",brandName);
DEBUG] 17:54:37.342 [main] c.w.m.B.selectByCondition - ==>  Preparing: select * from tb_brand where status = ? and company_name like ? 
[DEBUG] 17:54:37.363 [main] c.w.m.B.selectByCondition - ==> Parameters: 1(Integer), %华为%(String) 
[DEBUG] 17:54:37.375 [main] c.w.m.B.selectByCondition - <==      Total: 1 
[Brand(id=2, brandName=华为, companyName=华为技术有限公司, ordered=100, description=华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界, status=1)]
[DEBUG] 17:54:37.382 [main] o.a.i.t.j.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@64ec96c6] 

看sql语句,就拼接了2两个

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

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语句。这个就可以使用 where 标签解决

  • where 标签 (推荐)

    • 作用:
      • 替换where关键字
      • 会动态的去掉第一个条件前的 and
      • 如果所有的参数没有值则不加where关键字
    <select id="selectByCondition" resultMap="brandResultMap">select *from tb_brand<where><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></where>
    </select>
    

    注意:需要给每个条件前都加上 and 关键字。

  • 自己解决:恒等式

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

1.5 单个条件(动态SQL)

在这里插入图片描述

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

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

通过一个案例来使用这些标签

1.5.1 编写接口方法

BrandMapper 接口中定义单条件查询的方法。

/*** 单条件动态查询* @param brand* @return*/
List<Brand> selectByConditionSingle(Brand brand);

1.5.2 编写SQL语句

BrandMapper.xml 映射配置文件中编写 statement,使用 resultMap 而不是使用 resultType

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

1.5.3 编写测试方法

test/java 下的 cn.whu.mapper 包下的 MybatisTest类中 定义测试方法

@Test
public void testSelectByConditionSingle() throws IOException {//接收参数int status = 1;String companyName = "华为";String brandName = "华为";// 处理参数companyName = "%" + companyName + "%";brandName = "%" + brandName + "%";//封装对象Brand brand = new Brand();//brand.setStatus(status);brand.setCompanyName(companyName);//brand.setBrandName(brandName);//1. 获取SqlSessionFactoryString 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.selectByConditionSingle(brand);System.out.println(brands);//5. 释放资源sqlSession.close();
}

执行测试方法结果如下:

在这里插入图片描述

万一啥条件都没有,也会出bug.
解决方式有2种:
1:<otherwise>
2、直接用之前的<where>

  • 使用<otherwise>
<select id="selectByConditionSingle" resultMap="brandResultMap">select *from tb_brandwhere<choose><!--相当于switch 选择其中一个--><when test="status != null"> /*相当于case*/status = #{status} /*单个条件,肯定没有and*/</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>
  • 使用<where>
<select id="selectByConditionSingle" resultMap="brandResultMap">select *from tb_brand<where><choose><!--相当于switch 选择其中一个--><when test="status != null">/*相当于case*/status = #{status} /*单个条件,肯定没有and*/</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>

没有指定条件,就应该查询所有


-----------------------Mybatis配置文件增删改---------------------------

1.6 添加数据

在这里插入图片描述

如上图是我们平时在添加数据时展示的页面,而我们在该页面输入想要的数据后添加 提交 按钮,就会将这些数据添加到数据库中。接下来我们就来实现添加数据的操作。

  • 编写接口方法

    在这里插入图片描述
    参数:除了id之外的所有的数据。id对应的是表中主键值,而主键我们是 自动增长 生成的。

  • 编写SQL语句
    在这里插入图片描述

  • 编写测试方法并执行

明确了该功能实现的步骤后,接下来我们进行具体的操作。

1.6.1 编写接口方法

BrandMapper 接口中定义添加方法。

 /*** 添加*/
void add(Brand brand);

1.6.2 编写SQL语句

BrandMapper.xml 映射配置文件中编写添加数据的 statement

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

1.6.3 编写测试方法

test/java 下的 cn.whu.mapper 包下的 MybatisTest类中 定义测试方法

注意mybatis会关闭自动提交: Setting autocommit to false on JDBC Connection
也就是需要你手动提交事务 (否则IDEA里显示添加成功,数据库里却查不到)

方法1: 手动提交事务: sqlSession.commit();
方法2:把自动提交事务打开:SqlSession sqlSession = sqlSessionFactory.openSession(true);

@Test
public void testAdd() throws Exception {// 接收参数String brandName = "菠萝手机";String companyName = "菠萝有限公司";int ordered = 100;String description = "美国有苹果,中国有菠萝";int status = 1;// 参数封装成对象Brand brand = new Brand();brand.setBrandName(brandName);brand.setCompanyName(companyName);brand.setOrdered(ordered);brand.setDescription(description);brand.setStatus(status); //默认启用//1. 获取sqlSessionFactoryInputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);//2. 获取sqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//SqlSession sqlSession = sqlSessionFactory.openSession(true);//这里把自动提交事务打开也行//3. 获取mapper接口的代理对象BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法mapper.add(brand);// mybatis需要手动提交事务sqlSession.commit();//5. 释放资源sqlSession.close();
}

执行结果如下:

[DEBUG] 19:57:26.363 [main] o.a.i.t.j.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3e2055d6] 
[DEBUG] 19:57:26.365 [main] c.w.m.B.add - ==>  Preparing: insert into tb_brand(brand_name, company_name, ordered, description, status) value(?,?,?,?,?) 
[DEBUG] 19:57:26.384 [main] c.w.m.B.add - ==> Parameters: 菠萝手机(String), 菠萝有限公司(String), 100(Integer), 美国有苹果,中国有菠萝(String), 1(Integer) 
[DEBUG] 19:57:26.385 [main] c.w.m.B.add - <==    Updates: 1 
[DEBUG] 19:57:26.385 [main] o.a.i.t.j.JdbcTransaction - Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3e2055d6] 
[DEBUG] 19:57:26.386 [main] o.a.i.t.j.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3e2055d6] 
[DEBUG] 19:57:26.386 [main] o.a.i.t.j.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3e2055d6] 

1.6.4 添加-主键返回

在数据添加成功后,有时候需要获取插入数据库那行数据的主键(主键是自增长)。

比如:添加订单和订单项,如下图就是京东上的订单

在这里插入图片描述

订单数据存储在订单表中,订单项存储在订单项表中。

  • 添加订单数据

    在这里插入图片描述

  • 添加订单项数据,订单项中需要设置所属订单的id

    在这里插入图片描述

明白了什么时候 主键返回 。接下来我们简单模拟一下,在添加完数据后打印id属性值,能打印出来说明已经获取到了。

我们将上面添加品牌数据的案例中映射配置文件里 statement 进行修改,如下

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

在 insert 标签上添加如下属性:

  • useGeneratedKeys:是够获取自动增长的主键值。true表示获取
  • keyProperty :指定将获取到的主键值封装到哪儿个属性里

不配置,直接添加完直接用brand.getId(),得到的是null,没用
(这里也能看出不合理,自己插入的行数据,竟然有行内信息是自己不知道的)

再测试执行,testAdd()代码无需改动,add()方法后添加一行:

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

即可

  • 小结:
    在这里插入图片描述

1.7 修改

在这里插入图片描述

如图所示是修改页面,用户在该页面书写需要修改的数据,点击 提交 按钮,就会将数据库中对应的数据进行修改。注意一点,如果哪儿个输入框没有输入内容,我们是将表中数据对应字段值替换为空白还是保留字段之前的值?答案肯定是保留之前的数据。

接下来我们就具体来实现

1.7.1 编写接口方法

BrandMapper 接口中定义修改方法。

 /*** 修改 : 返回值int 就是影响的行数*/
int update(Brand brand);

上述方法参数 Brand 就是封装了需要修改的数据,而id肯定是有数据的,这也是和添加方法的区别。

--------修改全部字段--------

1.7.2 编写SQL语句

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

1.7.3 编写测试方法

BrandMapper.xml 映射配置文件中编写修改数据的 statement

    public void testUpdate() throws Exception {// 接收参数int id = 9;//要修改哪条数据String brandName = "菠萝手机2";String companyName = "菠萝无限公司";int ordered = 100;String description = "美国有苹果,中国有菠萝";int status = 1;// 参数封装成对象Brand brand = new Brand();brand.setId(id);brand.setBrandName(brandName);brand.setCompanyName(companyName);brand.setOrdered(ordered);brand.setDescription(description);brand.setStatus(status); //默认启用//1. 获取sqlSessionFactoryInputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);//2. 获取sqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//SqlSession sqlSession = sqlSessionFactory.openSession(true);//这里把自动提交事务打开也行//3. 获取mapper接口的代理对象BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法int count = mapper.update(brand);System.out.println(count);//count影响的行数// 返回值 影响的行数 可以获取到 输出为: 1// mybatis需要手动提交事务sqlSession.commit();//5. 释放资源sqlSession.close();}

执行结果如下:确实修改了所有的字段
在这里插入图片描述

--------动态修改部分字段--------

1.7.2 编写SQL语句

提交了的值修改,未提交的值不修改(保持原来的旧值) 多好的需求啊

<set>标签可以解决两个问题:1 是万一最后一个条件不成立引发的逗号,问题。2 是万一所有字段都为空,set多余的问题

BrandMapper.xml 映射配置文件中编写修改数据的 statement

<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 标签可以用于动态包含需要更新的列,忽略其它不更新的列。

1.7.3 编写测试方法

test/java 下的 cn.whu.mapper 包下的 MybatisTest类中 定义测试方法

@Test
public void testUpdate() throws Exception {// 接收参数int id = 9;//要修改哪条数据String brandName = "菠萝手机2";String companyName = "菠萝无限公司";int ordered = 100;String description = "美国有苹果,中国有菠萝";int status = 0;// 参数封装成对象Brand brand = new Brand();/* 只设置两个值了 */brand.setId(id);brand.setStatus(status);//1. 获取sqlSessionFactoryInputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);//2. 获取sqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//SqlSession sqlSession = sqlSessionFactory.openSession(true);//这里把自动提交事务打开也行//3. 获取mapper接口的代理对象BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法int count = mapper.update(brand);System.out.println(count);//count影响的行数// 返回值 影响的行数 可以获取到// mybatis需要手动提交事务sqlSession.commit();//5. 释放资源sqlSession.close();
}

执行测试方法结果如下:

在这里插入图片描述
从结果中SQL语句可以看出,只修改了 status 字段值,因为我们给的数据中只给Brand实体对象的 status 属性设置值了。这就是 set 标签的作用。

1.8 删除一行数据

在这里插入图片描述

如上图所示,每行数据后面都有一个 删除 按钮,当用户点击了该按钮,就会将该行数据删除掉。那我们就需要思考,这种删除是根据什么进行删除呢?是通过主键id删除,因为id是表中数据的唯一标识。

接下来就来实现该功能。

1.8.1 编写接口方法

BrandMapper 接口中定义根据id删除方法。

/*** 根据id删除*/
void deleteById(int id);

1.8.2 编写SQL语句

BrandMapper.xml 映射配置文件中编写删除一行数据的 statement

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

1.8.3 编写测试方法

test/java 下的 cn.whu.mapper 包下的 MybatisTest类中 定义测试方法

@Test
public void testDeleteById() throws Exception {// 接收参数int id = 12;//要删除哪条数据//1. 获取sqlSessionFactoryInputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);//2. 获取sqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//SqlSession sqlSession = sqlSessionFactory.openSession(true);//这里把自动提交事务打开也行//3. 获取mapper接口的代理对象BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法mapper.deleteById(id);// mybatis需要手动提交事务sqlSession.commit();//5. 释放资源sqlSession.close();
}

在这里插入图片描述

运行过程只要没报错,直接到数据库查询数据是否还存在。发现确实删除了

  • 小结:
    在这里插入图片描述

1.9 批量删除

在这里插入图片描述

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

1.9.1 编写接口方法

BrandMapper 接口中定义删除多行数据的方法。

/*** 批量删除*/
void deleteByIds(int[] ids);

参数是一个数组,数组中存储的是多条数据的id

1.9.2 编写SQL语句 (foreach 标签)

BrandMapper.xml 映射配置文件中编写删除多条数据的 statement

编写SQL时需要遍历数组来拼接SQL语句。Mybatis 提供了 foreach 标签供我们使用

foreach 标签

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

  • collection 属性:
    • mybatis会将数组参数,封装为一个Map集合。
      • 默认:array = 数组
      • 使用@Param注解改变map集合的默认key的名称
  • item 属性:本次迭代获取到的元素。
  • separator 属性:集合项迭代之间的分隔符。foreach 标签不会错误地添加多余的分隔符。也就是最后一次迭代不会加分隔符。
  • open 属性:该属性值是在拼接SQL语句之前拼接的语句,只会拼接一次
  • close 属性:该属性值是在拼接SQL语句拼接后拼接的语句,只会拼接一次
<delete id="deleteByIds">delete from tb_brand where idin<foreach collection="array" item="id" separator="," open="(" close=")">#{id}</foreach>;
</delete>

假如数组中的id数据是{1,2,3},那么拼接后的sql语句就是:

delete from tb_brand where id in (1,2,3);

1.9.3 编写测试方法

test/java 下的 com.itheima.mapper 包下的 MybatisTest类中 定义测试方法

@Test
public void testDeleteByIds() throws IOException {//接收参数int[] ids = {5,7,8};//1. 获取SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//SqlSession sqlSession = sqlSessionFactory.openSession(true);//3. 获取Mapper接口的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//4. 执行方法brandMapper.deleteByIds(ids);//提交事务sqlSession.commit();//5. 释放资源sqlSession.close();
}

相关文章:

02-MyBatis查询-

文章目录Mybatis CRUD练习1&#xff0c;配置文件实现CRUD1.1 环境准备Debug01: 别名mybatisx报错1.2 查询所有数据1.2.1 编写接口方法1.2.2 编写SQL语句1.2.3 编写测试方法1.2.4 起别名解决上述问题1.2.5 使用resultMap解决上述问题1.2.6 小结1.3 查询详情1.3.1 编写接口方法1.…...

外盘国际期货招商:2023年3月关注日历,把握重要投资机会

2023年3月大事件日历 关注大事日历&#xff0c;把握重要投资机会 3月1日&#xff1a;马斯克推出特斯拉宏图第三篇章 3月1-2日&#xff1a;G20外长会议 3月4-5日&#xff1a;全国两会召开 3月9日&#xff1a;中国2月CPI、PPI数据 待定&#xff08;前次进行日期&#xff1a…...

Linux学习(9.1)文件系统的简单操作

以下内容转载自鸟哥的Linux私房菜 原文&#xff1a;鸟哥的 Linux 私房菜 -- Linux 磁盘与文件系统管理 (vbird.org) 磁盘与目录的容量 df&#xff1a;列出文件系统的整体磁盘使用量&#xff1b;du&#xff1a;评估文件系统的磁盘使用量(常用在推估目录所占容量) df du 实体…...

Hadoop综合案例 - 聊天软件数据

目录1、聊天软件数据分析案例需求2、基于Hive数仓实现需求开发2.1 建库2.2 建表2.3 加载数据2.4 ETL数据清洗2.5 需求指标统计---都很简单3、FineBI实现可视化报表3.1 FineBI介绍3.2 FineBI配置数据3.3 构建可视化报表1、聊天软件数据分析案例需求 MR速度慢—引入hive 背景&a…...

Python进阶-----面向对象1.0(对象和类的介绍、定义)

目录 前言&#xff1a; 面向过程和面向对象 类和对象 Python中类的定义 &#xff08;1&#xff09;类的定义形式 &#xff08;2&#xff09;深层剖析类对象 前言&#xff1a; 感谢各位的一路陪伴&#xff0c;我学习Python也有一个月了&#xff0c;在这一个月里我收获满满…...

天猫淘宝企业服务为中小微企业打造供应链智能协同网络,让采购不再将就!丨爱分析报告

编者按&#xff1a;近日天猫淘宝企业服务&爱分析联合发布《2023中小微企业电商采购白皮书》&#xff0c;为中小微企业采购数字化带来红利。 某水泵企业&#xff1a;线上客户主要是中小微企业&#xff0c;线上业绩遇到瓶颈&#xff0c;如何突破呢&#xff1f;某焊割设备企业…...

基于四信网络摄像机的工业自动化应用

方案背景 随着数控机床被广泛的应用在工业生产中&#xff0c;数控技术发展成为制造业的核心。 鉴于数控机床的复杂性&#xff0c;以及企业人力储备有限&#xff0c;设备的监控和维护必须借助外部力量&#xff0c;而如何实现车间实时监测成了目前迫切解决的问题。 方案需求 ①兼…...

软件测试2

一 web掐断三大核心技术 HTML&#xff1a;负责网页的结构 CSS&#xff1a;负责网页的美化 JS&#xff1a;负责网页的行为 二 工具的使用 改变HBuilder文字的大小&#xff1a; 工具-视觉主题设置-大小22-确定 三 html简介 中文定义&#xff1a;超文本标记语言 新建一个html…...

(二分查找)leetcode162. 寻找峰值

文章目录一、题目1、题目描述2、基础框架3、原题链接二、解题报告1、思路分析2、时间复杂度3、代码详解三、本题小知识一、题目 1、题目描述 峰值元素是指其值严格大于左右相邻值的元素。 给你一个整数数组 nums&#xff0c;找到峰值元素并返回其索引。数组可能包含多个峰值…...

spring boot 配合element ui vue实现表格的批量删除(前后端详细教学,简单易懂,有手就行)

目录 一.前言&#xff1a; 二. 前端代码&#xff1a; 2.1.element ui组件代码 2.2删除按钮 2.3.data 2.4.methods 三.后端代码&#xff1a; 一.前言&#xff1a; 研究了其他人的博客&#xff0c;找到了一篇有含金量的&#xff0c;进行了部分改写实现前后端分离&#xff0…...

hiveSQL开窗函数详解

hive开窗函数 文章目录hive开窗函数1. 开窗函数概述1.1 窗口函数分类1.2 窗口函数和普通聚合函数的区别2. 窗口函数的基本用法2.1 基本用法2.2 设置窗口的方法2.2.1 window_name2.2.2 partition by2.2.3 order by 子句2.2.4 rows指定窗口大小窗口框架2.3 开窗函数中加 order by…...

深度学习基础实例与总结

一、神经网络 1 深度学习 1 什么是深度学习&#xff1f; 简单来说&#xff0c;深度学习就是一种包括多个隐含层 (越多即为越深)的多层感知机。它通过组合低层特征&#xff0c;形成更为抽象的高层表示&#xff0c;用以描述被识别对象的高级属性类别或特征。 能自生成数据的中…...

在 WIndows 下安装 Apache Tinkerpop (Gremlin)

一、安装 JDK 首先安装 Java JDK&#xff0c;这个去官网下载即可&#xff0c;我下载安装的 JDK19&#xff08;jdk-19_windows-x64_bin.msi&#xff09;&#xff0c;细节不赘述。 二、去 Tinkerpop 网站下载 Gremlin 网址&#xff1a;https://tinkerpop.apache.org/ 点击下面…...

从软件的角度看待PCI和PCIE(一)

1.最容易访问的设备是什么&#xff1f; 是内存&#xff01; 要读写内存&#xff0c;知道它的地址就可以了&#xff0c;不需要什么驱动程序&#xff1b; volatile unsigned int *p 0xffff8811; unsigned int val; *p val; val *p;只有内存能这样简单、方便的使用吗&#xf…...

DSP_TMS320F28377D_ADC学习笔记

前言 DSP各种模块的使用&#xff0c;基本上就是 GPIO复用配置、相关控制寄存器的配置、中断的配置。本文主要记录本人对ADC模块的学习笔记。TMS320F28377D上面有24路ADC专用IO&#xff0c;这意味着不需要进行GPIO复用配置。 只需要考虑相关控制寄存器和中断的配置。看代码请直…...

springcloud3 Nacos中namespace和group,dataId的联系

一 Namespance和group和dataId的联系 1.1 3者之间的联系 话不多说&#xff0c;上答案&#xff0c;如下图&#xff1a; namespance用于区分部署环境&#xff0c;group和dataId用于逻辑上区分两个目标对象。 二 案例&#xff1a;实现读取注册中心的不同环境下的配置文件 …...

[YOLO] yolo理解博客笔记

YOLO v2和V3 关于设置生成anchorbox&#xff0c;Boundingbox边框回归的过程详细解读 YOLO v2和V3 关于设置生成anchorbox&#xff0c;Boundingbox边框回归的个人理解https://blog.csdn.net/shenkunchang1877/article/details/105648111YOLO v1网络结构计算 Yolov1-pytorch版 …...

清华源pip安装Python第三方包

一、更换PIP源PIP源在国外&#xff0c;速度慢&#xff0c;可以更换为国内源&#xff0c;以下是国内一些常用的PIP源。豆瓣(douban) http://pypi.douban.com/simple/ (推荐)清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/阿里云 http://mirrors.aliyun.com/pypi/simple/中…...

python线程池【ThreadPoolExecutor()】批量获取博客园标题数据

转载&#xff1a;蚂蚁学python 网址&#xff1a;【【2021最新版】Python 并发编程实战&#xff0c;用多线程、多进程、多协程加速程序运行】 https://www.bilibili.com/video/BV1bK411A7tV/?p8&share_sourcecopy_web&vd_sourced0ef3d08fdeef1740bab49cdb3e96467实战案…...

LearnOpenGL-入门-8.坐标系统

本人刚学OpenGL不久且自学&#xff0c;文中定有代码、术语等错误&#xff0c;欢迎指正 我写的项目地址&#xff1a;https://github.com/liujianjie/LearnOpenGLProject LearnOpenGL中文官网&#xff1a;https://learnopengl-cn.github.io/ 文章目录坐标系统概述局部空间世界空…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...