Mybatis 操作数据库的基本 CRUD 以及查询操作详析

news2024/11/15 23:00:28

目录

1. 什么是 MyBaits ?

2. 搭建 MyBaits 环境

3. 了解 MyBaits 设计模式

MyBaits 操作数据库:

前置工作:

(1)建库建表

(2) 添加实体类

(3)添加 Mapper 接口

(4)添加 UserMapper.xml 

理解两种返回类型:

(1)resultType

(2)resultMap

1. 查询操作:

1.1 简单查询

1.2 条件查询

1.3 like 模糊查询

1.4 多表查询

2. 插入操作

3. 删除操作

4. 修改操作



关于 MyBaits 的知识点较深,细节较多,因此为了缓解阅读压力,其被分为两篇文章:

        1.Mybatis 操作数据库的基本CRUD  (本篇);

        2.Mybaits 之动态SQL的五大常用标签;


1. 什么是 MyBaits ?

        MyBaits 是一款功能极其强大的持久层框架,支持自定义 SQL、存储过程以及高级映射。Mybaits 是基于 JDBC 的,但其免除了几乎所有 JDBC 以及设置参数和获取结果集的工作。MyBaits 可以通过简单的 XML或注解来配置和映射原始类型、接口和 java 对象为数据库中的记录。

        简而言之:MyBaits 可以更加简洁的进行程序和数据库之间交互。

Mybaits 的学习路径:

        了解什么是MyBaits → 学会添加 Mybaits 框架到 java 项目中 → MyBaits 的初始化工作(连接数据库、配置 XML等)→ 学会基本的数据库CRUD操作 → 理解动态SQL(MyBaits的关键)→ 掌握常用几种动态 SQL 标签


2. 搭建 MyBaits 环境:

2.1 创建 Spring 项目,添加 Mybaits 框架依赖:

 2.2 设置 MyBaits 配置信息:

        (1)先在application.properties 配置文件中连接数据库:

                由于在引入依赖时专门引入了 MySQL Driver 这个数据库驱动,所以需要在这里为驱动设置类名,不过很简单,因为只要都是 MySQL,那么类名都是下面这个:

#设置 MySQL 驱动类名
spring.datasource.driver-class-name=com.mysql.cj.Driver

                MyBaits 要通过 XML 配置来映射数据库数据,那么就要有对于的 XML 文件,并且在 MyBaits 配置文件中 设置 XML 文件的路径:mapper-locatins。在 resource 目录下创建好响应的 XML 文件,如果统一的文件名都叫:xxxMapper.xml,那么就在路径设置时写为:*Mapper.xml

#设置 MyBaits 的 XML 路径 = 所有类的根目录:/mybatis目录下/所有名字以 Mapper.xml 结尾的 XML 文件都是当前mybatis要映射的
mybatis.mapper-locations=classpath:/mybatis/*Mapper.xml


3. 了解 MyBaits 设计模式:

        首先 Mybaits 的主要工具由两部分组成:interface + xml;

  • interface:MyBaits 既然是持久层的工具,那么要符合标准分层,就一定要接受其他层注入的接口、对象等;
  • xml:xml 文件中实现具体的 sql 语句;

        MyBaits 将 interface 和 xml 结合、封装起来,将本来不能被注入的 interface 变成一个可以被注入的代理对象,这个过程对用户是透明度。

        于是就可以实现:将数据库中的数据与对象建立映射关系,进而完成数据与对象之间的相互转换。

比如:

  • 数据库表 <——> 类;
  • 记录(行数据) <——> 对象;
  • 字段 <——> 对象的属性;

MyBaits 操作数据库:

        接下来开始真正的通过 MyBaits 去操作数据库了; 

前置工作:

(1)建库建表:

        准备工作:先在 MySQL 中创建一个mycnblog的数据库,再增添几张表:

-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8mb4;

-- 使用数据数据
use mycnblog;

-- 创建表[用户表]
drop table if exists  userinfo;
create table userinfo(
    id int primary key auto_increment,
    username varchar(100) not null,
    password varchar(32) not null,
    photo varchar(500) default '',
    createtime timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    `state` int default 1
) default charset 'utf8mb4';

-- 创建文章表
drop table if exists  articleinfo;
create table articleinfo(
    id int primary key auto_increment,
    title varchar(100) not null,
    content text not null,
    createtime timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    uid int not null,
    rcount int not null default 1,
    `state` int default 1
)default charset 'utf8mb4';

-- 创建视频表
drop table if exists videoinfo;
create table videoinfo(
  	vid int primary key,
  	`title` varchar(250),
  	`url` varchar(1000),
		createtime timestamp default current_timestamp,
		updatetime timestamp default current_timestamp,
  	uid int
)default charset 'utf8mb4';

-- 添加一个用户信息
INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES 
(1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1);

-- 文章添加测试数据
insert into articleinfo(title,content,uid)
    values('Java','Java正文',1);
    
-- 添加视频
insert into videoinfo(vid,title,url,uid) values(1,'java title','http://www.baidu.com',1);

(2) 添加实体类:

        要通过对象操作数据库,就得先有对于的实体类:这里先添加一个用户的实体类 USer,其与 userinfo 表对应。

        根据 userinfo 表中的字段信息,设置与实体类一对一的属性:

package com.example.demo.entity;
import lombok.Data;
import java.time.LocalDateTime;

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private Integer state;
}

(3)添加 Mapper 接口:

        Mapper 接口用来接收其他层注入的接口、方法、对象,通过结合 xml 来与数据库数据完成映射;Mapper 接口的创建都放在一个专门的 mapper 目录下;

        此处是专门来操作 userinfo 表的,它的实体类是 User,那么就先创建一个 UserMapper 接口:

        注意: MMapper 接口创建出来第一时间添加 @Mapper 注解!!!!

package com.example.demo.mapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
}

(4)添加 UserMapper.xml :

        这也正是上面所说的 MyBaits 两大工具中的第二个:MyBaits 的 xml 文件,也就是要和 Mapper 接口结合使用的 xml 文件(xml文件有很多人种,要分清楚),它正是数据持久层的具体实现。所有的这类 xml 文件的路径,都要和最开始配置的 mybatis-locations 路径一致;

        首先它有它的固定格式:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybati
s.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">

</mapper>

  •  <mapper><mapper>标签:需要指定 namespace 属性,意为命名空间,其值为 Mapper 接口的全包名.类名
  • mapper 标签内部的子标签:也即是黄色框内的<select>、<insert>、<update>等标签,用来实现具体 SQL; 
  • 子标签要注意的点:
    • id 要和 Mapper 接口中的方法名对应;
    • 返回类型根据需要填写;

理解两种返回类型:

        xml 里的返回类型有两种:resultTyperesultMap

        返回类型的作用是 MyBatis 做结果映射;

        如果是查询操作,返回类型必须设置;

        如果是增、删、改等操作,不强制设置返回类型;

(1)resultType:

        这是使用场景最多的类型,优点是非常方便,直接从全包名定义到类名即可

(2)resultMap:

        返回字典映射,有具体的使用场景:

  • 字段名和程序中的实体类的属性名不同的情况,可以配置 resultMap 映射;
  • 一对一和一对多关系可以使用 resultMap 映射;

演示第一种:字段名和属性名不同

数据库中的密码是 password,而 UserMapper 实体类中的属性名确实 pwd

 查询结果就会报错:检测不到 pwd

 借助 resultMap 设置映射关系:

<mapper namespace="com.example.demo.mapper.UserMapper">
    <resultMap id="baseMap" type="com.example.demo.entity.User">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="pwd"></result>
    </resultMap>
    
    <select id="getByPwd" resultMap="com.example.demo.mapper.UserMapper.baseMap">
        select * from userinfo where password=#{pwd}
    </select>
</mapper>

 此处运行结果就可以查出来:

         (大细节)不过如果在使用 @Param() 传参时就把属性名重命名成和字段名一样的话,也就不必大动干戈设置 resultMap 映射了;

resultMap 设置映射的原理:

         实际上,这个过程是以查询出结果为分界的,在接口拿到参数时,将该参数传递给 xml 里 {} 内部去匹配,接着将 SQL 和它拼接好传给数据库去实现,当数据库查询结束后要返回值给 MyBatis时,此时 resultMap 才会进行字段和属性的匹配;

第二种和第三种:一对一的表映射和一对多的表映射(了解即可,后续文章专门讲解,为了不增加不必要的篇幅)


1. 查询操作:

1.1 简单查询:

下面演示一个简单的查询功能:

(1)在 Mapper 接口中实现相关方法:

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
    // 查询所有用户
    List<User> getAllUser();
}

(2)在 UserMapper.xml 文件里实现具体的SQL:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybati
s.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <select id="getAllUser" resultType="com.example.demo.entity.User">
        select * from userinfo
    </select>
</mapper>

(3)实现 UserService 类 和 UserController 类:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public List<User> getAllUser() {
        return userMapper.getAllUser();
    }
}
@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/getAllUser")
    private List<User> getAllUSer() {
        return userService.getAllUser();
    }
}

启动后查看查询结果:

         鉴于 SQL 的执行要介绍很多种,如果全都通过 url 的方式来访问查看就很麻烦,所以采取一劳永逸的方法:设置打印 SQL 记录,并执行单元测试;

打印 mybatis 执行的 SQL:

在 application.properties 文件中继续配置,加上下面这两句:

#打印 MyBaits 执行的 SQL
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
logging.level.com.example/demo=debug

单元测试:

        在 Mapper 接口中,右键 - Generate - Test... - 勾选测试方法 - 生成测试类及测试方法 - 给测试类添加注解 @SpringBootTest - 注入 UserMapper 对象 - 实现具体的测试方法

 到这里做好一切配置和简化操作,下面继续介绍增、删、改、查等操作;

1.2 条件查询:

        凡是条件查询,就会涉及到条件匹配,站在用户角度就是要给方法传参,SQL去匹配参数;

        动态参数参数匹配有两种方法:

  1. #{paramName} —— 占位符模式;
  2. ${paramName} —— 直接替换;

        下面使用这两种匹配分别演示实例:

#{} 形式:

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
    // 按照姓名查询
    User getUserByName(@Param("username") String username);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybati
s.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <select id="getUserByName" resultType="com.example.demo.entity.User">
        select * from userinfo where username=#{username}
    </select>
</mapper>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    void getUserByName() {
        String username = "zhangSan";
        User user = userMapper.getUserByName(username);
        System.out.println(user);
    }
}

${} 形式: 

        其他不用变,只修改 UserMapper.xml 里的 SQL 语句部分: 

<select id="getUserByName" resultType="com.example.demo.entity.User">
        select * from userinfo where username='${username}'
    </select>

        正如结果所示,因为 ${} 是直接替换的逻辑,也就是说我们在写字符串时不能忘记自己加单引号,而 #{} 是占位符的逻辑,它会自动为我们传递的参数做适应性调整;

1.3 like 模糊查询:

        特殊情况:如果进行 like 模糊查询,又该用这两种的哪一种呢?

如果使用 #{} :会报错,因为它会自动给匹配到的参数加一对单引号

 如果使用 ${} : 虽然可以查出来,但其实不能直接使用,为了防止 SQL 注入的危险!!!

SQL 注入:

        下面这个示例,原本查询时要匹配用户名和密码都正确的,但是这个时候的password的输入很特殊,它实现了 SQL 注入,就像拿了一把本不属于这扇门的钥匙,但因为尺寸相似就打开了门,看到了里面的所有信息。 

        为什么查出来了?and 后面还有一个 or ,只要后面 or 的条件满足了,就全查出来了;

<<< 正确的模糊查询应该借助内置的 concat 拼接函数进行字符拼接: >>>

<select id="getUserByLike" resultType="com.example.demo.entity.User">
        select * from userinfo where username like concat('%',#{username},'%')
    </select>


1.4 多表查询:

        为了演示多表查询,就需要有其他表的实体类,这里选择当前库中的 articleinfo 表对应的 Article 类做其实体类;

        先增加 Article 实体类:

@Data
public class Article {
    private int id;
    private String title;
    private String content;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private int uid;
    private int rcount;
    private int state;
}

        考虑到文章表内没有作者信息,所以我们再添加一个 ArticleVO 实体类作为扩展类,继承 Article 类,也就是当查到想要的文章详情时,不仅显示文章表内的列字段,再把对应的作者也显示出来;

public class ArticleVO extends Article { 
    private String username; // 表示查询出来的文章是哪个作者写的
}

        上面这样做也是在解耦合,试想在企业中如果某个业务进行多表查询时要互相增添的字段非常非常多,总不能去每个实体类的内部增添一遍所有需要的属性,因此使用扩展类去继承可以降低冗余度和耦合性,提高开发效率;

下面开始多表查询:

        查询 mycnblog 库中的 articleinfo 表 和 userinfo 表,目标查出 文章详情描述以及其对应作者,文章详情在 articleinfo 表中,作者信息在 userinfo 表中;

        首先清楚,多表查询,主表应该是 articleinfo 表,userinfo 表的 username 字段应该是外连接部分,因此这次的查询方法以及 SQL 都要在 articleinfo 表的基础上完成;

(1)新增 ArticleMapper 接口,添加多表查询方法:

@Mapper // 一定不要忘记注解
public interface ArticleMapper {
    // 多表查询
    ArticleVO getFromTwoTables(@Param("id") int id);
}

(2)实现 ArticleMapper.xml 中的 SQL:

<mapper namespace="com.example.demo.mapper.ArticleMapper">
    <select id="getFromTwoTables" resultType="com.example.demo.entity.vo.ArticleVO">
        select a.*, u.username from articleinfo a
        join userinfo u on a.uid=u.id
        where a.id=#{id}
    </select>
</mapper>

(3)添加测试方法:

@SpringBootTest
class ArticleMapperTest {
    @Autowired
    private ArticleMapper articleMapper;

    @Test
    void getFromTwoTables() {
        int id = 1;
        ArticleVO articleVO = articleMapper.getFromTwoTables(id);
        System.out.println("文章详情:" + articleVO);
    }
}

执行结果:

        如果上面的查询一系列操作都掌握了,那么对下面的增、删、改就可以信手拈来了~


2. 插入操作:

       从这里开始增删改操作可能会影响数据表的内容,如果单纯测试不修改,就可以在单元测试方法上面加 @Transactional 注解,意为添加事务操作,操作完表的数据后进行回滚。

        新增、删除、修改这些操作的 xml 中可以不加返回类型;

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
    // 新增用户
    int addUser(User user);
}
<insert id="addUser">
        insert into userinfo (username,password) values(#{username}, #{password})
    </insert>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    void addUser() {
        String username = "zhaoLiu";
        String password = "666666";
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        int ret = userMapper.addUser(user);
        System.out.println("新增了 " +  ret + " 行");
    }
}


 3. 删除操作:

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
    // 删除用户
    int deleteUserByName(@Param("username") String username);
}
<delete id="deleteUserByName">
        delete from userinfo where username=#{username}
    </delete>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;


    @Test
    void deleteUserByName() {
        String username = "zhaoLiu";
        int ret = userMapper.deleteUserByName(username);
        System.out.println("删除了 " + ret + " 行");
    }
}


4. 修改操作:

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
    // 修改操作
    int update(@Param("username")String username, @Param("password")String password);
}
<update id="update">
        update userinfo set username=#{username}
            where password=#{password}
    </update>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    
    @Test
    void update() {
        String username = "张三";
        String password = "111111";
        int ret = userMapper.update(username,password);
        System.out.println("修改了 " + ret + " 行");
    }
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/696836.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CPU上下文切换原理剖析

CPU上下文 CPU上下文其实是一些环境正是有这些环境的支撑&#xff0c;任务得以运行&#xff0c;而这些环境的硬件条件便是CPU寄存器和程序计数器。CPU寄存器是CPU内置的容量非常小但是速度极快的存储设备&#xff0c;程序计数器则是CPU在运行任何任务时必要的&#xff0c;里面…

亿级数据过滤算法----布隆过滤器

在程序的世界中&#xff0c;布隆过滤器是程序员的一把利器&#xff0c;利用它可以快速地解决项目中一些比较棘手的问题。如网页 URL 去重、垃圾邮件识别、大集合中重复元素的判断和缓存穿透等问题。 布隆过滤器&#xff08;Bloom Filter&#xff09;是 1970 年由布隆提出的。它…

水站桶装水订水小程序

水站桶装水订水小程序正式上线&#xff0c;支持多种商品展示形式&#xff0c;会员卡、积分、分销等功能&#xff0c;有需要的老板可以先看演示&#xff01;​​​​​​​​​​​​​​​​​​​​​

Java框架之spring 的 messaging

写在前面 本文看下spring message相关的内容。 1&#xff1a;Message&#xff1f;Messaging&#xff1f; Message是消息的意思&#xff0c;是一个名词。而Messaging是一个动名词&#xff0c;是将消息发送出去的意思&#xff0c;因此&#xff0c;我们的消息系统是messaging s…

SuperMap iServer 扩展账户信息合规度校验规则

作者&#xff1a;lisong 目录 功能简介配置文件详情扩展和配置流程 功能简介 SuperMap iServer 11i&#xff08;2023&#xff09; 新增了扩展账户信息合规度校验规则的能力&#xff0c;您可以灵活定制满足自身项目需求的用户名、密码合规度校验规则&#xff0c;用于校验您创建…

企业邮箱如何修改管理员密码

1、登录企业邮局&#xff0c;点击顶部“邮局管理”。在邮局管理中点击“组织与成员”,在用户列表中&#xff0c;点击“邮局管理员”&#xff08;postmaster&#xff09;。 2、在编辑用户中&#xff0c;点击“重置密码”,然后输入新的密码&#xff0c;保存即可。

java中的xxl-job-core完成定时任务的步骤

首先这个是基于docker的所以需要进行docker配置 1、先导入官方提供的SQL到虚拟机中mysql中 2、创建容器 docker run -e PARAMS"--spring.datasource.urljdbc:mysql://192.168.211.136:3306/xxl_job?useUnicodetrue&characterEncodingUTF-8&autoReconnecttrue&a…

2014年全国硕士研究生入学统一考试管理类专业学位联考数学试题——纯题目版

2014 年考研管理类联考数学真题 一、问题求解&#xff08;本大题共 15 小题&#xff0c;每小题 3 分&#xff0c;共 45 分&#xff09;下列每题给出 5 个选项中&#xff0c;只有一个是符合要求的&#xff0c;请在答题卡上将所选择的字母涂黑。 1.某部门在一次联欢活动中共设了 …

python接口自动化测试 - configparser配置文件解析器详细使用

configparser简介 ConfigParser模块已在Python 3中重命名为configparser该模块定义了ConfigParser类。 ConfigParser类实现一种基本的配置文件解析器语言&#xff0c;该语言提供的结构类似于 .ini 文件中的结构 Python自动化测试&#xff1a;手把手教你做60个实战项目&#xf…

设计模式(二十三)——解释器模式(Interpreter )

解释器模式&#xff08;Interpreter &#xff09; 实现了一个表达式接口&#xff0c;该接口解释一个特定的上下文 应用 编译器&#xff0c;正则表达式&#xff0c;SQL解析 实现 实现一个一位数的加法运算 public class Interpreter {public int add(String s){if (s.char…

代码复现:基于精英动态反向学习的增强型正余弦算法—EDOLSCA,可用于对比试验

代码复现&#xff1a;基于精英动态反向学习的增强型正余弦算法—EDOLSCA&#xff0c;可用于对比试验。 参考文献&#xff1a;Zhang L, Hu T, Yang Z, et al. Elite and dynamic opposite learning enhanced sine cosine algorithm for application to plat-fin heat exchanger…

带你用Python制作超级经典的2048游戏(文末赠书)

名字&#xff1a;阿玥的小东东 学习&#xff1a;Python、C/C 主页链接&#xff1a;阿玥的小东东的博客_CSDN博客-python&&c高级知识,过年必备,C/C知识讲解领域博主 目录 2048游戏Python实现 本期赠书 2048游戏Python实现 2048游戏是一款非常流行的益智游戏&#xff0…

vue-cli的Nuxt重构

我的博客用vuecli写的&#xff0c;SEO不忍直视。于是用Nuxt重构了代码&#xff0c;过程中踩了无数坑 一&#xff1a;body样式不生效 正常的body样式设置不能生效&#xff0c;需要在nuxt.config.js中配置 1、设置bodyAttrs的class属性&#xff0c;该属性值对应一个类名 2、该…

Unity 聚焦任意大小的物体

聚焦任意大小的物体 &#x1f371;效果&#x1f96a;食用方法 &#x1f371;效果 &#x1f96a;食用方法 &#x1f4a1;.安装Cinemachine &#x1f4a1;.把Assets/ZYF/Tools/Camera/Scene/FocusGo/FocusCtrl.prefab拖入场景 &#x1f4a1;.调用FocusCtrl.Focus(gameObject)即可…

《kafka 核心技术与实战》课程学习笔记(九)

客户端都有哪些不常见但是很高级的功能&#xff1f; 什么是 Kafka 拦截器&#xff1f; 拦截器基本思想就是允许应用程序在不修改逻辑的情况下&#xff0c;动态地实现一组可插拔的事件处理逻辑链。它能够在主业务操作的前后多个时间点上插入对应的“拦截”逻辑。Spring MVC 拦…

接口跨域问题

只要协议不同/端口号不同/域名不同都会导致跨域问题

深入浅出设计模式 - 中介者模式

博主介绍&#xff1a; ✌博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家✌ Java知识图谱点击链接&#xff1a;体系化学习Java&#xff08;Java面试专题&#xff09; &#x1f495;&#x1f495; 感兴趣的同学可以收…

C++之lambda表达式回调函数作为参数(一百四十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

【python】matplotlib 绘制火山图、条形图

文章目录 火山图条形图 火山图 绘制火山图&#xff0c;输入是两个datafreme&#xff0c;行是样本名&#xff0c;列是基因名。使用T-test检验绘制基因表达情况。 def minmax_scale(data):import numpy as np# # 示例数据# data np.array([2, 4, 6, 8, 10])# 进行Min-Max标准化…

go并发编程之channel

目录 1.简介 2.channel类型 无缓冲区的channel 无缓冲区channel的创建 带缓冲区的channel 带缓冲区channel的创建 3.channel使用代码演示 4.获取channel中的值 ​编辑 5.单向channel 单向发送data&#xff0c;发送到channel中 单向接收&#xff0c;channel接收数据 6…