SpringCloudAlibaba【六】微服务架构下的秒杀案例

news2024/11/20 4:53:51

背景

分布式微服务中的秒杀是怎么实现的呢?接着看下去吧

我们实现一个秒杀微服务,流程逻辑如下

在这里插入图片描述

项目搭建

MySQL

create database if not exists demo;

use demo;

drop table if exists skill_goods;

create table if not exists skill_goods (
    id bigint(20) key,
    name varchar(200),
    price decimal(10,2),
    cost_price decimal(10,2),
    status char,
    num int,
    stock_count int,
    introduction varchar(200)
);

drop table if exists skill_order;

create table if not exists skill_order (
    id bigint key,
    skill_id bigint,
    money decimal,
    user_id varchar(20),
    create_time datetime,
    pay_time datetime,
    status char
);

在这里插入图片描述

在这里插入图片描述

IDEA中构建Maven父项目,再建两个子项目Product和Skill

在这里插入图片描述

POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>springcloud-nacos</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>skill</module>
        <module>product</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <!--add-->

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--nacos-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>cn.itlym.shoulder</groupId>
            <artifactId>lombok</artifactId>
            <version>0.1</version>
        </dependency>

        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.69</version>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.5.RELEASE</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

Product模块

创建如下目录结构

在这里插入图片描述

YML

server:
  port: 9000
spring:
  cloud:
    nacos:
      discovery:
        service: prod-serv
      server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/demo?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: root
    password: fengzhizi98!

  redis:
    host: localhost
    port: 6379

ProductApplication

package com.product;

import com.fasterxml.jackson.databind.ser.std.NumberSerializers;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class ProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class);
    }

    @Bean
    public RedisTemplate<Object, Object> redisTemplate (RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        template.setKeySerializer(new StringRedisSerializer());
        return template;
    }

}

ProductController

package com.product.controller;

import com.product.entity.Goods;
import com.product.service.GoodService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

@RestController
public class ProductController {

    @Resource
    private GoodService goodService;

    @GetMapping("/product/{productId}")
    public Goods product(@PathVariable Long productId) {
        System.out.println("调用商品服务");
        return goodService.queryGoods(productId);
    }

    @PostMapping("/product")
    public String update(@RequestBody Goods goods) {
        goodService.update(goods);
        return "更新库存成功";
    }

}

GoodService

package com.product.service;

import com.alibaba.fastjson.JSON;
import com.product.dao.GoodsDao;
import com.product.entity.Goods;
import com.product.utils.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Component
public class GoodService {

    public static final String SKILL_GOODS_PHONE = "SKILL_GOODS_PHONE";
    public static final String SKILL_GOODS_QUEUE = "SKILL_GOODS_QUEUE";

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private GoodsDao goodsDao;

    @Scheduled(fixedDelay = 5000)
    public void prepareGood() {
        System.out.println("开始加载商品");

        Set<Long> set = redisTemplate.boundHashOps(SKILL_GOODS_PHONE).keys();
        List<Long> ids = new ArrayList<>();
        for (Long id : set) {
            ids.add(id);
        }

        List<Goods> list = null;
        //只查询出不在内存当中的商品信息,并加载到内存
        if (CollectionUtils.isEmpty(ids)) {
            list = goodsDao.findAllGoods();
        } else {
            list = goodsDao.findGoods(ids);
        }

        if (!CollectionUtils.isEmpty(list)) {
            for (Goods goods : list) {
                redisTemplate.boundHashOps(SKILL_GOODS_PHONE).put(goods.getId(), JSON.toJSONString(goods));
                redisTemplate.boundListOps(SKILL_GOODS_QUEUE+goods.getId()).leftPush(convertToArray(goods.getStock_count(), goods.getId()));
            }
        }

        //查看当前缓存中所有的商品信息
        Set keys = redisTemplate.boundHashOps(SKILL_GOODS_PHONE).keys();
        for (Object s : keys) {
            Goods goods = JSONUtil.toEntity((String) redisTemplate.boundHashOps(SKILL_GOODS_PHONE).get(s), Goods.class);
            System.out.println(goods.getName() + " 库存剩余:" + goods.getStock_count());
        }
    }

    private Long[] convertToArray(Integer stock_count, Long id) {
        Long[] idlong = new Long[stock_count];
        for (int i = 0; i < stock_count; i++) {
            idlong[i] = id;
        }
        return idlong;
    }

    //查询商品信息
    public Goods queryGoods (Long productId) {
        return JSONUtil.toEntity((String) redisTemplate.boundHashOps(SKILL_GOODS_PHONE).get(productId), Goods.class);
    }

    //更新商品信息
    public void update(Goods goods) {
        goodsDao.save(goods);
    }

}

GoodsDao

package com.product.dao;

import com.product.entity.Goods;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface GoodsDao extends JpaRepository<Goods, Long> {

    @Query(value = "select * from skill_goods where status = 1 and num > 0 and stock_count > 0 and id not in (?1)", nativeQuery = true)
    List<Goods> findGoods(List<Long> ids);

    @Query(value = "select * from skill_goods where status = 1 and num > 0 and stock_count > 0", nativeQuery = true)
    List<Goods> findAllGoods();

}

Goods

package com.product.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;

@Entity
@Table(name = "skill_goods")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Goods implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "price")
    private BigDecimal price;

    @Column(name = "cost_price")
    private BigDecimal cost_price;

    @Column(name = "status")
    private String status;

    @Column(name = "num")
    private Integer num;

    @Column(name = "stock_count")
    private Integer stock_count;

    @Column(name = "introduction")
    private String introduction;

}

JSONUtil

说明:为了使Redis的序列化简化,我们使用JSON来存储对象信息,该工具主要功能使JSON和实体的转换

package com.product.utils;

import com.alibaba.fastjson.JSON;

public class JSONUtil {

    /***
     * 将JSON文本反序列化到对象
     */
    public static <T> T toEntity(String jsonString, Class<T> bean) {
        T t = (T) JSON.parseObject(jsonString, bean); // fastjson
        return t;
    }

}

Skill模块

创建如下目录结构

在这里插入图片描述

YML

server:
  port: 13000
spring:
  cloud:
    nacos:
      discovery:
        service: skill-serv
      server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/demo?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: root
    password: fengzhizi98!

  redis:
    host: localhost
    port: 6379

SkillApplication

package com.skill;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableAsync
public class SkillApplication {

    public static void main(String[] args) {
        SpringApplication.run(SkillApplication.class);
    }

    @Bean
    public RedisTemplate<Object, Object> redisTemplate (RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        template.setKeySerializer(new StringRedisSerializer());
        return template;
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }


}

SkillApplication

package com.skill.controller;

import com.skill.service.SkillGoodsService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class SkillController {

    @Resource
    private SkillGoodsService skillGoodsService;

    @GetMapping("/skill")
    public String skill(String userId, Long productId) {
        try{
            skillGoodsService.add(productId, userId);
            return "秒杀成功";
        } catch (Exception e) {
            return e.getMessage();
        }
    }

}

SkillGoodsService

package com.skill.service;

import com.alibaba.fastjson.JSON;
import com.skill.entity.SkillEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.UUID;

@Service
public class SkillGoodsService {

    public static final String SKILL_GOODS_LIST = "SKILL_GOODS_LIST";

    public static final String SKILL_GOODS_ONLY = "SKILL_GOODS_ONLY";

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private MultiThreadOrder multiThreadOrder;

    @Transactional
    public void add(Long productId, String userId) {

        //模拟多用户
        userId = UUID.randomUUID().toString();

        //判断用户是否参加过抢单
        Long time = redisTemplate.boundHashOps(SKILL_GOODS_ONLY).increment(userId, 1L);
        try {
            if (time > 1) {
                throw new Exception("重复抢单,不要贪心");
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        //封装对象放入Redis队列
        SkillEntity skill = new SkillEntity();
        skill.setProductId(productId);
        skill.setUserId(userId);

        redisTemplate.boundListOps(SKILL_GOODS_LIST).leftPush(JSON.toJSONString(skill));

        try {
            multiThreadOrder.createOrder();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }

}

ProductService

package com.skill.service;

import com.skill.entity.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class ProductService {

    @Autowired
    private RestTemplate restTemplate;

    public Goods queryByProductId(Long productId) {
        return restTemplate.getForObject("http://prod-serv/product/" + productId, Goods.class);
    }

    public void update(Goods goods) {
        ResponseEntity<String> result = restTemplate.postForEntity("http://prod-serv/product", goods, String.class);
        System.out.println(result.getBody());
    }

}

MultiThreadOrder

package com.skill.service;

import com.skill.dao.SkillOrderDao;
import com.skill.entity.Goods;
import com.skill.entity.SkillEntity;
import com.skill.entity.SkillOrder;
import com.skill.utils.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MultiThreadOrder {

    public static final String SKILL_GOODS_PHONE = "SKILL_GOODS_PHONE";

    public static final String SKILL_GOODS_LIST = "SKILL_GOODS_LIST";

    public static final String SKILL_GOODS_QUEUE = "SKILL_GOODS_QUEUE";

    private static final String SKILL_GOODS_ONLY = "SKILL_GOODS_ONLY";

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SkillOrderDao skillOrderDao;

    @Autowired
    private ProductService productService;

    @Async
    public void createOrder() {
        System.out.println("开始异步抢单");

        SkillEntity skill = JSONUtil.toEntity((String) redisTemplate.boundListOps(SKILL_GOODS_LIST).rightPop(), SkillEntity.class);
        if (skill == null) {
            return;
        }
        Long productId = skill.getProductId();
        String userId = skill.getUserId();

        Goods goods = productService.queryByProductId(productId);

        try {
            if (goods == null) {
                throw new Exception("商品被抢光");
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        Long stockId = (Long) redisTemplate.boundListOps(SKILL_GOODS_QUEUE + productId).rightPop();
        if (stockId == null) {
            System.out.println("该商品已被秒杀完毕");
            redisTemplate.boundHashOps(SKILL_GOODS_ONLY).delete(userId);
            redisTemplate.boundHashOps(SKILL_GOODS_PHONE).delete(goods.getId());
            goods.setStock_count(0);
            productService.update(goods);
            return;
        }

        SkillOrder skillOrder = new SkillOrder();
        skillOrder.setMoney(goods.getCost_price());
        skillOrder.setPayTime(new Date());
        skillOrder.setStatus("0");
        skillOrder.setUserId(userId);
        skillOrder.setCreateTime(new Date());
        skillOrder.setSkillId(productId);

        skillOrderDao.save(skillOrder);

        System.out.println("结束异步抢单");
    }
}

SkillOrderDao

package com.skill.dao;

import com.skill.entity.SkillOrder;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface SkillOrderDao extends JpaRepository<SkillOrder, Long> {
}

Goods

package com.skill.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;

@Entity
@Table(name = "skill_goods")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Goods implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "price")
    private BigDecimal price;

    @Column(name = "cost_price")
    private BigDecimal cost_price;

    @Column(name = "status")
    private String status;

    @Column(name = "num")
    private Integer num;

    @Column(name = "stock_count")
    private Integer stock_count;

    @Column(name = "introduction")
    private String introduction;

}

SkillEntitiy

package com.skill.entity;

import lombok.Data;

import java.io.Serializable;

@Data
public class SkillEntity implements Serializable {
    private Long productId;

    private String userId;
}

SkillOrder

package com.skill.entity;


import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

@Data
@Entity
@Table(name = "skill_order")
public class SkillOrder implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private String id;

    @Column(name = "skill_id")
    private Long skillId;

    @Column(name = "money")
    private BigDecimal money;

    @Column(name = "user_id")
    private String userId;

    @Column(name = "create_time")
    private Date createTime;

    @Column(name = "pay_time")
    private Date payTime;

    @Column(name = "status")
    private String status;
}

JSONUtil

package com.skill.utils;

import com.alibaba.fastjson.JSON;

public class JSONUtil {

    /***
     * 将JSON文本反序列化到对象
     */
    public static <T> T toEntity(String jsonString, Class<T> bean) {
        T t = (T) JSON.parseObject(jsonString, bean); // fastjson
        return t;
    }

}

测试

先启动Redis,Sentinel,MySQL,Nacos

Nacos

在这里插入图片描述

Sentinel

在这里插入图片描述

Redis

在这里插入图片描述

MySQL

在这里插入图片描述

启动项目

在这里插入图片描述

Apifox高并发测试

在这里插入图片描述

结果

IPHONE12 已经被抢光了

在这里插入图片描述

数据库IPHONE12的库存也清零了

在这里插入图片描述

项目代码

项目代码

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

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

相关文章

1024程序员节|【MySQL从入门到精通】【高级篇】(二十七)外连接和内连接如何进行查询优化呢?join的原理了解一波

您好&#xff0c;我是码农飞哥&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通 ❤️ 2.网上优质的Python题库很少…

[面试宝典] Linux常见命令及面试题

前言&#xff1a; &#x1f604;作者简介&#xff1a;小曾同学.com,小伙伴们也可以叫我小曾&#xff0c;一个致力于测试开发的博主⛽️ 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;…

C语言 - 你一定能看懂的扫雷万字详解(加入了递归展开和手动标雷的功能)

C语言之扫雷详解&#xff08;包含递归展开和手动标雷功能&#xff0c;非常强大&#xff01;&#xff09; 文章目录一.写在前面二.效果展示三.整体逻辑四.详解1.进入主函数&#xff0c;打印菜单&#xff0c;玩家作出选择2.定义棋盘的数组并进行赋值3.棋盘的展示4.随机布雷5.开始…

前端开发入门--html--Flask

快速开发网站 pip install flaskfrom flask import Flaskapp Flask(__name__)# 创建了网址 /show/info 和 函数index 的对应关系 # 以后用户在浏览器上访问 /show/info&#xff0c;网站自动执行 index app.route("/show/info") def index():return "中国联通&…

TPH-YOLOv5 | 基于Transformer的YOLOv5小目标检测器 | 四头加注意力

论文地址&#xff1a;https://arxiv.org/pdf/2108.11539.pdf 项目地址&#xff1a;https://github.com/cv516Buaa/tph-yolov5 在无人机捕获的场景中进行对象检测是最近的一项热门任务。由于无人机总是在不同的高度航行&#xff0c;物体尺度变化剧烈&#xff0c;给网络优化带来…

NMEA协议解析

文章目录一、NMEA0183协议1、NMEA基本框架2、常用语句1&#xff09;GNGGA2&#xff09;GNGLL3&#xff09;GNGSA4&#xff09;GPGSV5&#xff09;GNRMC6&#xff09;GNVTG7&#xff09;GNZDA8&#xff09;PAIRCLK等二、异或校验和代码1、网址在线计算BCC2、BCC校验和代码一、NM…

Java语言中的异常处理

异常处理 在java语言中&#xff0c;很机智的将异常作为对象来处理&#xff0c;而且定义一个基类java.lang.Throwable作为所有异常类的父类。在这许多类中一般分为两大类&#xff1a; 错误类(Error)和异常类&#xff08;Expception&#xff09;。 如图&#xff1a; 注&#xf…

iNOF在现实网络中的运用,以带反射器的iONF为例

定义 iNOF&#xff08;Intelligent Lossless NVMe Over Fabric&#xff0c;智能无损存储网络&#xff09;是指通过对接入主机的快速管控&#xff0c;将智能无损网络应用到存储系统&#xff0c;实现计算和存储网络融合的技术。 目的 网络转发设备用于传输流量&#xff0c;不同类…

竞争不是内卷,用头脑学习,而非时间

文章目录 用头脑学习&#xff0c;而非时间 前言 一、自由竞争不是内卷 二、内卷都在哪些行业 三、高效学习来大数据梦想联盟 用头脑学习&#xff0c;而非时间 前言 大多数人不懂&#xff0c;不会&#xff0c;不做&#xff0c;才是你的机会&#xff0c;你得行动&#xff…

【Queue】- 从源码分析ArrayDeque及其常用方法

文章目录概述ArrayDeque基础知识ArrayDeque内部结构ArrayDeque的构造方法ArrayDeque的扩容操作ArrayDeque常用方法将ArrayDeque作为双端队列使用时public void addFirst(E e)public void addLast(E e)public boolean offerFirst(E e)public boolean offerLast(E e)public E pol…

动态SLAM论文归纳

持续更新&#xff0c;持续更新 2022 Multi-modal Semantic SLAM for Complex Dynamic Environments 作者&#xff1a;Han Wang, Jing Ying Ko and Lihua Xie, Fellowcode&#xff1a;https://github.com/wh200720041/MMS_SLAM视频&#xff1a;https://www.youtube.com/watch…

web自动化测试——入门篇01

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

并发编程中的原子性,可见性,有序性问题

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;在一家满意的公司实习。本篇文章是关于并发编程中出现的原子性&#xff0c;可见性&#xff0c;有序性问题。 本篇文章记录的基础知识&#xff0c;适合在学Java的小白&#xff0c;也适合复习中&am…

PyTorch(三)TensorBoard 与 Transforms

文章目录Log一、TensorBoard1. TensorBoard 的安装2. SummaryWriter 的使用① add_scalar() 的使用a. 参数说明b. 函数使用c. 使用 Tensorboard② add_image() 的使用a. 参数说明b. 使用 numpy.array() 对 PIL 图片进行转换c. 使用函数d. 改变 global_step二、Transforms1. Tra…

数据结构 | 时间复杂度与空间复杂度

… &#x1f333;&#x1f332;&#x1f331;本文已收录至&#xff1a;数据结构 | C语言 更多知识尽在此专栏中&#xff01; &#x1f389;&#x1f389;&#x1f389;欢迎点赞、收藏、关注 &#x1f389;&#x1f389;&#x1f389;文章目录&#x1f333;前言&#x1f333;正…

【C++初阶】类和对象(二)

大家好我是沐曦希&#x1f495; 类和对象1.类的6个默认成员函数2.构造函数2.1 概念2.2 特性3.析构函数3.1 概念3.2 特性4.拷贝构造函数4.1 概念4.2 特征1.类的6个默认成员函数 空类&#xff1a;类中一个成员都没有 可是空类真的什么都没有吗&#xff1f; 并不是&#xff0c;任…

STM32关于UART的接收方式

STM32的 UART 一般分为定长接收和不定长接收 定长接收&#xff1a; HAL_UART_Receive():只能接收固定长度的数据&#xff0c;如果超过固定长度的数据只能接收对应长度&#xff0c;如果小于固定长度则不会接收 HAL_UART_Receive_IT():中断方式接收&#xff0c;每接收一个字节…

CSS 2 CSS 选择器 - 5 2.8 伪选择器 2.8.1 伪类选择器【根据特定状态选取元素】

CSS 文章目录CSS2 CSS 选择器 - 52.8 伪选择器2.8.1 伪类选择器【根据特定状态选取元素】2 CSS 选择器 - 5 2.8 伪选择器 2.8.1 伪类选择器【根据特定状态选取元素】 【什么是伪类】 伪类用于定义元素的特殊状态。 例如&#xff0c;它可以用于&#xff1a; 设置鼠标悬停在…

如何删除ZIP压缩包的密码?

ZIP是比较常用的压缩文件格式&#xff0c;有时候因为工作需要很多人还会给压缩包设置打开密码。那如果后续不需要密码保护了要如何删除密码呢&#xff1f;密码忘记了还能删除吗&#xff1f; 首先来说说第一种情况&#xff0c;也就是知道密码但后续不需要密码保护&#xff0c;只…

1. 初识Python

1. Pythond 简介 Python 语言由荷兰的 Guido Van Rossum (吉多范罗苏姆, 江湖人称龟叔) 在1989年圣诞节期间为了打发圣诞节的无趣而开发的一个脚本解释语言.Python 源代码遵循 GPL(GNU General Public License)开源协议, 也就是说你可以免费使用和传播它, 而不用担心版权的问…