电子产业一站式赋能平台

PCB联盟网

搜索
查看: 227|回复: 0
收起左侧

海康威视,开了体面的薪资!

[复制链接]

320

主题

320

帖子

2688

积分

三级会员

Rank: 3Rank: 3

积分
2688
发表于 2024-11-1 17:02:00 | 显示全部楼层 |阅读模式
大家好,我是库森。
* }5 s. |; l. z. Z海康威视作为一家体面厂,我们来看看今年海康威视的校招薪资开了多少?
; t1 w) z" a/ l5 p3 D  \我根据一些同学的反馈,整理了海康威视软件开发岗位的校招薪资,在目前的就业背景下,海康威视的校招薪资还是很体面的。+ A- f& t- U% C8 N- W
  • 14k x 15 = 21w(本科 985,武汉)
  • 15k x 15 =  22.5w(硕士双一流,杭州)
  • 16 x 15 =  24w (本硕 211,杭州)
  • 19 x 15 = 28.5w (本硕 211,杭州)那海康威视的面试难度如何呢?. W2 k, q2 i) b) b
    我也找了一位今年秋招面海康威视同学的面经,给大家做做参考参考,总共 1 轮技术面 + 1 轮 HR 面,3-5 个工作日出结果。% g! n8 p. O' Y: `4 Q
    一面是技术面,问的问题不算多,主要拷打了 Java、MySQL、Redis 方面的八股文,都属于经典的面试问题,不算难。
    $ e0 l  K! f4 N( w8 h( Q4 `

    fmvmujcputf64078576854.jpg

    fmvmujcputf64078576854.jpg
    % I  f3 d4 R7 o- i2 }  w
    Java 介绍一下 Spring Boot 整体的启动流程?
  • 首先从main找到run()方法,在执行run()方法之前new一个SpringApplication对象
  • 进入run()方法,创建应用监听器SpringApplicationRunListeners开始监听
  • 然后加载SpringBoot配置环境(ConfigurableEnvironment),然后把配置环境(Environment)加入监听对象中
  • 然后加载应用上下文(ConfigurableApplicationContext),当做run方法的返回对象
  • 最后创建Spring容器,refreshContext(context),实现starter自动化配置和bean的实例化等工作。[/ol]说一说 Spring MVC 整体的执行流程?6 }/ l% W4 o7 V6 f* D, h' \# R

    cxzzckxp1pl64078576954.jpg

    cxzzckxp1pl64078576954.jpg

    & |; h: O, [3 L) h7 }0 l流程图步骤详解:
  • 发送请求:用户发送的所有请求都会到前端控制器DispatcherServlet
  • 请求查找Handler:DispatcherServlet收到请求会调用HandlerMapping(处理器映射器)查找Handler
  • 返回Handler:处理器映射器根据url返回具体的处理器,生成HandlerExecutionChain对象,其中包含了目标Handler和若干拦截器(可能没有)
  • 请求调用Handler:DispatcherServlet通过Handler寻找匹配到HandlerAdapter
  • 执行Handler:HandlerAdapter调用Handler
  • 返回结果:Handler执行完成,返回一个ModelAndView对象
  • 返回结果给DispatcherServlet:HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet
  • 如果Handler返回的View是逻辑视图名称而不是真正的View对象,DispatcherServlet调用resolveViewName方法在配置的所有视图解析器(ViewResolver)中,寻找合适的,最终通过ViewResolver将逻辑视图名解析成真正的View对象
  • ViewResolver通过调用createView方法尝试将视图名解析成View,如果无法解析会返回Null(注: 如果ViewResolver是派生自AbstractCachingViewResolver则在调用createView方法前会先尝试根据viewName和Iocale从缓存中查找对应的视图对象)
  • DispatcherServlet调用View的render方法进行渲染视图 (即将模型数据填充至request域)
  • DispatcherServlet响应用户[/ol]MySQL MySQL 索引的机制,类型有哪些?MySQL可以按照四个角度来分类索引。
      a$ ~7 R* b: V9 x( g& F
  • 按「数据结构」分类:B+tree索引、Hash索引、Full-text索引
  • 按「物理存储」分类:聚簇索引(主键索引)、二级索引(辅助索引)
  • 按「字段特性」分类:主键索引、唯一索引、普通索引、前缀索引
  • 按「字段个数」分类:单列索引、联合索引接下来,按照这些角度来说说各类索引的特点。
    3 D8 h: _3 p) g! @; j% o/ W按数据结构分类, ~8 J7 I; t2 L8 K: x  r+ l3 d5 C
    从数据结构的角度来看,MySQL 常见索引有 B+Tree 索引、HASH 索引、Full-Text 索引。
    2 K4 {- s1 u' G# \+ @& h6 S0 K每一种存储引擎支持的索引类型不一定相同,我在表中总结了 MySQL 常见的存储引擎 InnoDB、MyISAM 和 Memory 分别支持的索引类型。
    $ D: Q2 h8 C. c! ^( l" J7 A

    zjro0uixxki64078577054.jpg

    zjro0uixxki64078577054.jpg

    2 v. Q+ I  H. G  \/ M: O2 S2 \InnoDB 是在 MySQL 5.5 之后成为默认的 MySQL 存储引擎,B+Tree 索引类型也是 MySQL 存储引擎采用最多的索引类型。) F: z, Y/ a. B. t" i8 x% Z, i4 o/ e
    在创建表时,InnoDB 存储引擎会根据不同的场景选择不同的列作为索引:
    ) q9 Y. e! a) z
  • 如果有主键,默认会使用主键作为聚簇索引的索引键(key);
  • 如果没有主键,就选择第一个不包含 NULL 值的唯一列作为聚簇索引的索引键(key);
  • 在上面两个都没有的情况下,InnoDB 将自动生成一个隐式自增 id 列作为聚簇索引的索引键(key);其它索引都属于辅助索引(Secondary Index),也被称为二级索引或非聚簇索引。创建的主键索引和二级索引默认使用的是 B+Tree 索引
    / ?* i' w4 p8 d6 i) `1 v. P6 A7 l按物理存储分类7 U/ u) y% c+ o4 K+ Z0 K
    从物理存储的角度来看,索引分为聚簇索引(主键索引)、二级索引(辅助索引)。
    ) ~! N0 j: Q$ S" v- c4 P" V这两个区别在前面也提到了:
    4 K4 X9 z3 H* C% E
  • 主键索引的 B+Tree 的叶子节点存放的是实际数据,所有完整的用户记录都存放在主键索引的 B+Tree 的叶子节点里;
  • 二级索引的 B+Tree 的叶子节点存放的是主键值,而不是实际数据。所以,在查询时使用了二级索引,如果查询的数据能在二级索引里查询的到,那么就不需要回表,这个过程就是覆盖索引。如果查询的数据不在二级索引里,就会先检索二级索引,找到对应的叶子节点,获取到主键值后,然后再检索主键索引,就能查询到数据了,这个过程就是回表。
    / Q! S( @# _$ t& K: T按字段特性分类" s5 y0 q4 p& |' J2 v' w6 U  d
    从字段特性的角度来看,索引分为主键索引、唯一索引、普通索引、前缀索引。
    8 Z, n8 S4 h7 x0 d
  • 主键索引主键索引就是建立在主键字段上的索引,通常在创建表的时候一起创建,一张表最多只有一个主键索引,索引列的值不允许有空值。% E+ W# E5 i4 I9 D7 Z6 g
    在创建表时,创建主键索引的方式如下:' P- F- |0 X& j8 C# w% S9 A6 t
    CREATE TABLE table_name  (" u/ K- y% Z/ F) ^
      ....! a+ Z& }6 r; H1 t& P. ^
      PRIMARY KEY (index_column_1) USING BTREE/ h4 m" R# b6 y. A8 V
    );  Q8 H8 h5 D* m$ `6 F$ [$ E1 s. Z
  • 唯一索引唯一索引建立在 UNIQUE 字段上的索引,一张表可以有多个唯一索引,索引列的值必须唯一,但是允许有空值。+ e, r- E; e* D/ k
    在创建表时,创建唯一索引的方式如下:  [9 M4 {% Y; E7 E+ }2 ]' a/ `- m9 G
    CREATE TABLE table_name  (+ H' J0 N' V) p7 B! r9 w) l4 E5 I
      ....- z  T  |" A1 P  ?7 ~: N" m* ]
      UNIQUE KEY(index_column_1,index_column_2,...) 6 g1 A; {' j& m
    );0 Q4 Q& @6 ~, r5 Q  z
    建表后,如果要创建唯一索引,可以使用这面这条命令:
    8 q) i8 q; y7 y& v7 \CREATE UNIQUE INDEX index_name
    6 e5 O9 x( [+ P: d6 G) _7 ION table_name(index_column_1,index_column_2,...);
    2 i% w( c% I  I! p! F
  • 普通索引普通索引就是建立在普通字段上的索引,既不要求字段为主键,也不要求字段为 UNIQUE。5 y6 H) W7 T& o" C1 ]; B
    在创建表时,创建普通索引的方式如下:) Z* }% G6 U. C7 m4 M
    CREATE TABLE table_name  (
    2 W7 }5 w3 O+ u  ....
    * O3 G7 R3 b) f; u6 {# w4 Y; v  INDEX(index_column_1,index_column_2,...) & C) C4 P; D! X! {# P$ X! w
    );
    # ?' y5 [* q2 i% v9 [建表后,如果要创建普通索引,可以使用这面这条命令:2 u2 Z; S$ I/ y
    CREATE INDEX index_name
    , n" f; v, p1 m1 l* Y$ H  GON table_name(index_column_1,index_column_2,...);* w" ?$ ~# ~8 v! L
  • 前缀索引前缀索引是指对字符类型字段的前几个字符建立的索引,而不是在整个字段上建立的索引,前缀索引可以建立在字段类型为 char、 varchar、binary、varbinary 的列上。7 h8 e2 c. f  v' o9 r
    使用前缀索引的目的是为了减少索引占用的存储空间,提升查询效率。) C+ v. r7 b( i  t$ _
    在创建表时,创建前缀索引的方式如下:& N2 {' R- R9 k+ t  r- X4 u2 Q, L( s& ]
    CREATE TABLE table_name(( |( Z/ Y. s6 b5 ?: g( ~# W( }2 j0 Z8 y
        column_list,
    ; s5 E3 Q% }5 a4 i0 P5 b/ c+ g    INDEX(column_name(length))& U/ q; H* ^9 x+ z
    );
      l6 s0 U9 A/ m' C建表后,如果要创建前缀索引,可以使用这面这条命令:
    / s3 h7 q  b# b+ b, {CREATE INDEX index_name
    % I1 E) v) U0 m' D; t! `2 Z. ^+ PON table_name(column_name(length));
    , E% f" h, B+ G  w) Q3 U按字段个数分类
    ! c# T$ x2 S  b3 x! Z% n: G
    从字段个数的角度来看,索引分为单列索引、联合索引(复合索引)。
    . N5 M  V/ `" J1 t
  • 建立在单列上的索引称为单列索引,比如主键索引;
  • 建立在多列上的索引称为联合索引;通过将多个字段组合成一个索引,该索引就被称为联合索引。1 r& g& N9 w/ \5 f" {: g% v
    比如,将商品表中的 product_no 和 name 字段组合成联合索引(product_no, name),创建联合索引的方式如下:
    : z! U: k0 U* u7 s0 f0 v) kCREATE INDEX index_product_no_name ON product(product_no, name);$ G6 K' T9 R3 z7 V2 ~6 G- w$ t
    联合索引(product_no, name) 的 B+Tree 示意图如下(图中叶子节点之间我画了单向链表,但是实际上是双向链表,原图我找不到了,修改不了,偷个懒我不重画了,大家脑补成双向链表就行)。3 H8 [8 [7 S3 b5 ^( Y' a* y6 B

    ibea4h5cthi64078577154.jpg

    ibea4h5cthi64078577154.jpg
    ' M( r) M+ U$ t8 J/ {+ J: U
    可以看到,联合索引的非叶子节点用两个字段的值作为 B+Tree 的 key 值。当在联合索引查询数据时,先按 product_no 字段比较,在 product_no 相同的情况下再按 name 字段比较。
    + q( e" ^* Y: g" }0 Q8 H# l, t$ K也就是说,联合索引查询的 B+Tree 是先按 product_no 进行排序,然后再 product_no 相同的情况再按 name 字段排序。) A/ C  J: N6 l1 w( c) P
    因此,使用联合索引时,存在最左匹配原则,也就是按照最左优先的方式进行索引的匹配。在使用联合索引进行查询的时候,如果不遵循「最左匹配原则」,联合索引会失效,这样就无法利用到索引快速查询的特性了。
      u! ^/ o  g' n5 ~, y$ E比如,如果创建了一个 (a, b, c) 联合索引,如果查询条件是以下这几种,就可以匹配上联合索引:
    % S, k' l7 \6 M+ f$ {) [; g3 ?
  • where a=1;
  • where a=1 and b=2 and c=3;
  • where a=1 and b=2;需要注意的是,因为有查询优化器,所以 a 字段在 where 子句的顺序并不重要。3 U' ]+ ]8 `4 E  \' f2 o5 {+ @# @
    但是,如果查询条件是以下这几种,因为不符合最左匹配原则,所以就无法匹配上联合索引,联合索引就会失效:2 S' J; c5 G( D% c3 B5 j
  • where b=2;
  • where c=3;
  • where b=2 and c=3;上面这些查询条件之所以会失效,是因为(a, b, c) 联合索引,是先按 a 排序,在 a 相同的情况再按 b 排序,在 b 相同的情况再按 c 排序。所以,b 和 c 是全局无序,局部相对有序的,这样在没有遵循最左匹配原则的情况下,是无法利用到索引的。
    ( J( \4 z% m# J; {- [联合索引有一些特殊情况,并不是查询过程使用了联合索引查询,就代表联合索引中的所有字段都用到了联合索引进行索引查询,也就是可能存在部分字段用到联合索引的 B+Tree,部分字段没有用到联合索引的 B+Tree 的情况。
    " Z4 v+ R/ h2 X, C6 n+ m6 b这种特殊情况就发生在范围查询。联合索引的最左匹配原则会一直向右匹配直到遇到「范围查询」就会停止匹配。也就是范围查询的字段可以用到联合索引,但是在范围查询字段的后面的字段无法用到联合索引7 e; v: n' f! L& _
    有无排查索引失效的经验,展开讲讲?可以使用 EXPLAIN 来查看 SQL 的执行计划,判断SQL是否走了索引,如果没有走索引,就代表索引发生失效了。1 K8 \( K3 x( z
    如下图,就是一个没有使用索引,并且是一个全表扫描的查询语句。0 U, j! L" @5 Y/ c+ [( B

    53a05fgp4c264078577254.jpg

    53a05fgp4c264078577254.jpg

    - ?9 }" R& k0 S: x/ z8 d对于执行计划,参数有:
    + c( L( @. r+ }0 O
  • possible_keys 字段表示可能用到的索引;
  • key 字段表示实际用的索引,如果这一项为 NULL,说明没有使用索引;
  • key_len 表示索引的长度;
  • rows 表示扫描的数据行数。
  • type 表示数据扫描类型,我们需要重点看这个。type 字段就是描述了找到所需数据时使用的扫描方式是什么,常见扫描类型的执行效率从低到高的顺序为+ o# a1 g7 L7 A3 c$ e
  • All(全表扫描):在这些情况里,all 是最坏的情况,因为采用了全表扫描的方式。
  • index(全索引扫描):index 和 all 差不多,只不过 index 对索引表进行全扫描,这样做的好处是不再需要对数据进行排序,但是开销依然很大。所以,要尽量避免全表扫描和全索引扫描。
  • range(索引范围扫描):range 表示采用了索引范围扫描,一般在 where 子句中使用 、in、between 等关键词,只检索给定范围的行,属于范围查找。从这一级别开始,索引的作用会越来越明显,因此我们需要尽量让 SQL 查询可以使用到 range 这一级别及以上的 type 访问方式
  • ref(非唯一索引扫描):ref 类型表示采用了非唯一索引,或者是唯一索引的非唯一性前缀,返回数据返回可能是多条。因为虽然使用了索引,但该索引列的值并不唯一,有重复。这样即使使用索引快速查找到了第一条数据,仍然不能停止,要进行目标值附近的小范围扫描。但它的好处是它并不需要扫全表,因为索引是有序的,即便有重复值,也是在一个非常小的范围内扫描。
  • eq_ref(唯一索引扫描):eq_ref 类型是使用主键或唯一索引时产生的访问方式,通常使用在多表联查中。比如,对两张表进行联查,关联条件是两张表的 user_id 相等,且 user_id 是唯一索引,那么使用 EXPLAIN 进行执行计划查看的时候,type 就会显示 eq_ref。
  • const(结果只有一条的主键或唯一索引扫描):const 类型表示使用了主键或者唯一索引与常量值进行比较,比如 select name from product where id=1。需要说明的是 const 类型和 eq_ref 都使用了主键或唯一索引,不过这两个类型有所区别,const 是与常量进行比较,查询效率会更快,而 eq_ref 通常用于多表联查中extra 显示的结果,这里说几个重要的参考指标:2 _4 [4 s* y9 Y4 ?7 l) G3 Q3 O
  • Using filesort :当查询语句中包含 group by 操作,而且无法利用索引完成排序操作的时候, 这时不得不选择相应的排序算法进行,甚至可能会通过文件排序,效率是很低的,所以要避免这种问题的出现。
  • Using temporary:使了用临时表保存中间结果,MySQL 在对查询结果排序时使用临时表,常见于排序 order by 和分组查询 group by。效率低,要避免这种问题的出现。
  • Using index:所需数据只需在索引即可全部获得,不须要再到表中取数据,也就是使用了覆盖索引,避免了回表操作,效率不错。索引失效的场景有哪些?会发生索引失效的情况:. ^7 k/ `" K* w- @
  • 当我们使用左或者左右模糊匹配的时候,也就是 like %xx 或者 like %xx%这两种方式都会造成索引失效;
  • 当我们在查询条件中对索引列使用函数,就会导致索引失效。
  • 当我们在查询条件中对索引列进行表达式计算,也是无法走索引的。
  • MySQL 在遇到字符串和数字比较的时候,会自动把字符串转为数字,然后再进行比较。如果字符串是索引列,而条件语句中的输入参数是数字的话,那么索引列会发生隐式类型转换,由于隐式类型转换是通过 CAST 函数实现的,等同于对索引列使用了函数,所以就会导致索引失效。
  • 联合索引要能正确使用需要遵循最左匹配原则,也就是按照最左优先的方式进行索引的匹配,否则就会导致索引失效。
  • 在 WHERE 子句中,如果在 OR 前的条件列是索引列,而在 OR 后的条件列不是索引列,那么索引会失效。Redis Redis 为什么这么快?官方使用基准测试的结果是,单线程的 Redis 吞吐量可以达到 10W/每秒,如下图所示:
    & d* \& k( q: t  ^9 M% _3 E. k* C8 S- k

    h1twxfhtg3w64078577354.jpg

    h1twxfhtg3w64078577354.jpg

    , t+ Y6 |2 P( V, ]7 j之所以 Redis 采用单线程(网络 I/O 和执行命令)那么快,有如下几个原因:
    0 s' y, W" ]7 o, L" J2 q
  • Redis 的大部分操作都在内存中完成,并且采用了高效的数据结构,因此 Redis 瓶颈可能是机器的内存或者网络带宽,而并非 CPU,既然 CPU 不是瓶颈,那么自然就采用单线程的解决方案了;
  • Redis 采用单线程模型可以避免了多线程之间的竞争,省去了多线程切换带来的时间和性能上的开销,而且也不会导致死锁问题。
  • Redis 采用了 I/O 多路复用机制处理大量的客户端 Socket 请求,IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听 Socket 和已连接 Socket。内核会一直监听这些 Socket 上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。Redis 6.0 之后为什么引入了多线程?Redis 单线程指的是「接收客户端请求->解析请求 ->进行数据读写等操作->发送数据给客户端」这个过程是由一个线程(主线程)来完成的,这也是我们常说 Redis 是单线程的原因。
    * O5 K2 l$ m5 F7 E: M' L1 U; F5 R+ _, e但是,Redis 程序并不是单线程的,Redis 在启动的时候,是会启动后台线程(BIO)的:
    0 d( E: I: u& l7 {" {( ^
  • Redis 在 2.6 版本,会启动 2 个后台线程,分别处理关闭文件、AOF 刷盘这两个任务;
  • Redis 在 4.0 版本之后,新增了一个新的后台线程,用来异步释放 Redis 内存,也就是 lazyfree 线程。例如执行 unlink key / flushdb async / flushall async 等命令,会把这些删除操作交给后台线程来执行,好处是不会导致 Redis 主线程卡顿。因此,当我们要删除一个大 key 的时候,不要使用 del 命令删除,因为 del 是在主线程处理的,这样会导致 Redis 主线程卡顿,因此我们应该使用 unlink 命令来异步删除大key。之所以 Redis 为「关闭文件、AOF 刷盘、释放内存」这些任务创建单独的线程来处理,是因为这些任务的操作都是很耗时的,如果把这些任务都放在主线程来处理,那么 Redis 主线程就很容易发生阻塞,这样就无法处理后续的请求了。6 T4 z) M8 a; ^! _1 p* r" q. ]# V
    后台线程相当于一个消费者,生产者把耗时任务丢到任务队列中,消费者(BIO)不停轮询这个队列,拿出任务就去执行对应的方法即可。
    1 o0 W  l1 t$ C) O

    znfflvyj2bj64078577454.jpg

    znfflvyj2bj64078577454.jpg
    / |$ G7 g1 g8 ]! W  N
    虽然 Redis 的主要工作(网络 I/O 和执行命令)一直是单线程模型,但是在 Redis 6.0 版本之后,也采用了多个 I/O 线程来处理网络请求这是因为随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上& Q6 @9 w+ C# F# I1 W  m
    所以为了提高网络 I/O 的并行度,Redis 6.0 对于网络 I/O 采用多线程来处理。但是对于命令的执行,Redis 仍然使用单线程来处理,所以大家不要误解Redis 有多线程同时执行命令, w, B: _. ^6 U' [7 E  `
    Redis 官方表示,Redis 6.0 版本引入的多线程 I/O 特性对性能提升至少是一倍以上, O; r- f- @$ r
    Redis 6.0 版本支持的 I/O 多线程特性,默认情况下 I/O 多线程只针对发送响应数据(write client socket),并不会以多线程的方式处理读请求(read client socket)。要想开启多线程处理客户端读请求,就需要把 Redis.conf 配置文件中的 io-threads-do-reads 配置项设为 yes。: S( {8 e9 x& n; {; S; X1 g6 k
    //读请求也使用io多线程/ @4 M$ d$ E' b3 _( w8 _
    io-threads-do-reads yes, y$ x! _8 `2 u0 E$ A, J
    同时, Redis.conf 配置文件中提供了 IO 多线程个数的配置项。
    $ p$ I4 B: L/ k; @% W// io-threads N,表示启用 N-1 个 I/O 多线程(主线程也算一个 I/O 线程): \1 M1 K; q9 o6 n: h1 R
    io-threads 4  g5 \- E  H; J. i+ @$ A) s
    关于线程数的设置,官方的建议是如果为 4 核的 CPU,建议线程数设置为 2 或 3,如果为 8 核 CPU 建议线程数设置为 6,线程数一定要小于机器核数,线程数并不是越大越好。3 ^4 I  s- E0 ?  L; @
    因此, Redis 6.0 版本之后,Redis 在启动的时候,默认情况下会额外创建 6 个线程(这里的线程数不包括主线程):
    % |  H7 y* \% F6 g' ~9 N. t
  • Redis-server :Redis的主线程,主要负责执行命令;
  • bio_close_file、bio_aof_fsync、bio_lazy_free:三个后台线程,分别异步处理关闭文件任务、AOF刷盘任务、释放内存任务;
  • io_thd_1、io_thd_2、io_thd_3:三个 I/O 线程,io-threads 默认是 4 ,所以会启动 3(4-1)个 I/O 多线程,用来分担 Redis 网络 I/O 的压力。Redis 分布式锁怎么解决超卖问题的?同一个锁key,同一时间只能有一个客户端拿到锁,其他客户端会陷入无限的等待来尝试获取那个锁,只有获取到锁的客户端才能执行下面的业务逻辑。9 s6 o- b1 W3 H+ K4 V+ L
    比如说,用户要一次性买 10 台手机,那么避免超卖的流程如下:; Z* B! c" ^+ o1 {1 z) Z) o: x
  • 只有一个订单系统实例可以成功加分布式锁,然后只有他一个实例可以查库存、判断库存是否充足、下单扣减库存,接着释放锁。
  • 释放锁之后,另外一个订单系统实例才能加锁,接着查库存,一下发现库存只有 2 个了,库存不足,无法购买,下单失败,不会将库存扣减为-8的,就避免超卖的问题。这种方案的缺点是同一个商品在多用户同时下单的情况下,会基于分布式锁串行化处理,导致没法同时处理同一个商品的大量下单的请求。
  • 回复

    使用道具 举报

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则


    联系客服 关注微信 下载APP 返回顶部 返回列表