MyFirstDay_答案_1.**猫(自己整理)

1>***猫:

  1. python基础类:

    1. 字符串反转的常用处理方式:
      # 方法一:使用字符串切片
      s = "hello python"
      result = s[::-1]
      print(result)
      # [Out]nohtyp olleh
      
      
      # 方法二:使用列表的reverse方法
      l = list(s)
      l.reverse()
      result = "".join(l)
      print(result)
      
      # 方法三:使用reduce
      from functools import reduce
      
      s = "hello python"
      
      result = reduce(lambda x, y: y + x, s)
      
      print(result)
      
      
      # 方法四:使用递归函数
      def func(s):
          if len(s) < 1:
              return s
          return func(s[1:]) + s[0]
      
      
      result = func(s)
      print(result)
      
      
      # 方法五:使用栈
      def func(s):
          l = list(s)  # 模拟全部入栈
          result = ""
          while len(l) > 0:
              result += l.pop()  # 模拟出栈
          return result
      
      
      result = func(s)
      print(result)
      
      
      # 方法六:for循环
      def func(s):
          result = ""
          max_index = len(s) - 1
          for index, value in enumerate(s):
              result += s[max_index - index]
          return result
      
      
      result = func(s)
      print(result)

       

      1. 你说一下python中的迭代器、生成器、装饰器

         

        # 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
          
        # 在Python中,这种一边循环一边计算的机制,称为生成器:generator
        
        # 在代码运行期间动态增加功能的方式,称之为“装饰器”: Decorator
        
        # 生成器和迭代器的区别:
        #     1、语法方面来讲:
        #         生成器是用函数中yield语句来创建的。迭代器的创建首先跟函数无关,可以用iter([1,2])来创建。
        #     2、使用方面来讲:
        #         由于生成器是使用函数的方式创建的,所以生成器里面的所有过程都会被执行,但请注意生成器里面的过程只有在被next()调用或者for循环调用时,里面的过程才会被执行

         

    2. 如果让你实现一个迭代器,你会怎么做
      # 迭代器有两个基本的方法:iter() 和 next()。
      # 字符串,列表或元组对象都可用于创建迭代器:
      list = [1, 2, 3, 4]
      it = iter(list)
      print(next(it))
      print(next(it))
      # 迭代器对象可以使用常规for语句进行遍历:
      list = [1, 2, 3, 4]
      it = iter(list)
      for x in it:
          print(x, end=" ")
      
      # 也可以使用 next() 函数:
      import sys
      
      list = [1, 2, 3, 4]
      it = iter(list)
      while True:
          try:
              print(next(it))
          except StopIteration:
              sys.exit()
      
      # 创建一个迭代器
      # 把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。
      # # 如果你已经了解的面向对象编程,就知道类都有一个构造函数,Python 的构造函数为 __init__(), 它会在对象初始化的时候执行。
      # __iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成.
      # __next__() 方法(Python 2 里是 next())会返回下一个迭代器对象。
      # 创建一个返回数字的迭代器,初始值为 1,逐步递增 1:
      # StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
      # 在 20 次迭代后停止执行:
      
      
      class MyNumbers:
          def __iter__(self):
              self.a = 1
              return self
      
          def __next__(self):
              if self.a <= 20:
                  x = self.a
                  self.a += 1
                  return x
              else:
                  raise StopIteration
      
      
      myclass = MyNumbers()
      myiter = iter(myclass)
      
      for x in myiter:
          print(x)

       

    3. 怎么样获取一个生成器?
      # 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

       

    4. 你有用过yield对象吗?得到的是一个什么样的对象?
      # 调用一个生成器函数,返回的是一个迭代器对象。
      # 以下实例使用 yield 实现斐波那契数列:
      import sys
      
      
      def fibonacci(n):
          a, b, counter = 0, 1, 0
          while True:
              if(counter > n):
                  return
              yield a
              a, b = b, a + b
              counter += 1
      f = fibonacci(10)   # f 是一个迭代器,由生成器返回生成
      
      while True:
          try:
              print(next(f), end=" ")
          except StopIteration:
              sys.exit()

       

    5. 你有了解过python中的协程吗?
      # 协程,又称微线程,纤程。英文名Coroutine。
      # 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用。
      # 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。
      # 所以子程序调用是通过栈实现的,一个线程就是执行一个子程序。
      # 子程序调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。
      # 协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。
      def consumer():
          r = ''
          while True:
              n = yield r
              if not n:
                  return
              print('[CONSUMER] Consuming %s...' % n)
              r = '200 OK'
      
      def produce(c):
          c.send(None)
          n = 0
          while n < 5:
              n = n + 1
              print('[PRODUCER] Producing %s...' % n)
              r = c.send(n)
              print('[PRODUCER] Consumer return: %s' % r)
          c.close()
      
      c = consumer()
      produce(c)

       

  2. 技能类:

    1. 你有用过git吗?
      Git是分布式版本控制系统
      集中式VS分布式:
      集中式版本控制系统,版本库集中存放在中央服务器,必须要联网才能工作,没有历史版本库。
      分布式版本控制系统,没有“中央服务器”,每个开发人员电脑上都有一个完整的版本库。
      分布式优势:安全性更高,无需联网,若“中央服务器”故障,任何一个其他开发者本地都有最新的带历史记录的版本库。
      主要区别在于历史版本库的存放,集中式历史版本只存在于中央服务器,而分布式中每个本地库都有历史记录存放。

       

    2. 你有合过代码吗?
      git status  
      查看下当前代码状态,有需要提交的就提交,没有需要提交的就保持原样
      git pull
      拉取远程代码,使得本地代码保持最新
      git branch -a 
      查看最新代码所在分支
      remotes/origin/HEAD -> origin/master
      最新的分支会有remotes/origin/HEAD ->指明
      git merge origin/master
      执行合并命令把最新分支代码合并到本地当前分支
      git diff
      查看冲突信息
      git status 
      查看下状态看看那些文件需要手工调整
      git add .
      把修改好的文件添加到索引
      git commit -m '合并XXX分支代码'
      提交代码
      git push
      把合并好的代码推送到远程
      
      如果合并过程中出现问题,可以使用以下命令回退到日志的合并之前的位置
      git reset --hard commit_id 

       

    3. 你有布署过代码吗?
    4. 布署的步骤是怎样的?你是怎么样把你的代码放到服务器中的?
      # 1、提交代码当在本地开发&测试完毕后,将代码合并到 master 分支,并 Push 到远程的 Git 仓库。
      # 通常在开发中使用 Git 作为代码版本管理工具,通过创建一个 dev 分支来进行开发工作,在发布的时候再将代码合并到 master 分支,这样可以保证 master 分支永远都是稳定的版本
      git push origin master
      # 2、拉取并部署代码到预发机通过以下命令从 Git 仓库获取到最新的代码
      git pull
      # 因为开发运行环境和线上运行环境的数据库、缓存等配置的差异,拉取的代码一般无法直接在预发机上直接运行。通常的做法是,在预发机上执行一个 shell 脚本,将线上的配置覆盖开发环境的配置。
      cp code/path/to/config-dist code/path/to/config
      # 预发机的主要作用是留出缓冲的空间,检验代码是否在线上环境可以正常工作。对于一个 Web 项目,我们可以设置域名的 host 配置,直接访问预发机。
      # 3、同步代码到线上一般情况下,一个 Web 项目都会有多个业务机,通过负载均衡将请求流量平均分配的 N 台机器,以提高服务的承载能力和可用性。
      # 因此,这里面临着一个发布代码到 N 台机器的问题。显然,我们不能一台台的发布,这样效率太低了。通常,我们通过在预发机上执行 shell 脚本,将代码 Rsync 到 N 台机器上。
      rsync /path/to/code user@127.0.0.1::path/to/code --exclude-list=exclude.list
      # 4、快速回滚发布完代码后,我们会在预发机的 Git 仓库上执行 :
      git tag v20160522
      # 记录此次发布的版本。如果在发布后发现出了问题,可以在预发机的 Git 仓库执行如下命令:
      git tag -l
      # 找出上一次发布的版本,并回滚代码:
      git reset --hard v20160521
      # 然后,再通过步骤 3 的方式,将回滚的代码同步到 N 台业务机上。
      #
      # 作者:Ceelog
      # 链接:https://www.jianshu.com/p/79dc6e0278e2
      # 来源:简书
      # 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

       

    5. docker你有使用过吗?谈一谈
      # docker镜像可以完全看作一台全新的电脑使用,无论什么镜像都是对某一东西进行了配置,然后打包后可以快速移植到需要的地方直接使用
      # 省去复杂的配置工作
      # 比如python web项目部署,如果是新部署,需要装系统,配置各类环境,费时费力还容易出错,
      # 而docker就可以省去配置环境的麻烦,直接把所需的包丢进去,实现分分钟部署一个项目
      # 给ubuntu安装docker,我安装的是docker ee:
      wget -qO- https://get.docker.com/ | sh
      # 安装好之后,便是启动docker
      sudo service docker start
      # 启动后,是没有任何镜像的,不过可以通过pull命令获取相关镜像
      sudo docker images
      sudo docker pull nginx
      sudo docker pull nginx 默认获取最新版本,即TAG为latest的,如果要获取其他版本,则需要使用 sudo docker pull nginx:xxxx
      # 获取镜像后,通过docker run使其运行起来
      sudo docker ps -a 列出所有容器, 不加 -a 仅列出正在运行的,像退出了的或者仅仅只是创建了的就不列出来
      sudo docker run -d -p 8800:80 --name nginx_xiao  nginx  #运行指定的镜像
      dudo docker run -d --privileged=true -p 83:80 --name nginx83 nginx   #提升权限
      #宿主主机端口:容器内部端口
      #   -d  后台运行
      #   -p 8800:80 是指定对外暴露的端口  容器内部用80 对应外部宿主主机的的8800  代理一样
      #   --name指定容器的名字  最后的nginx 代码要运行的镜像名字  有tag的加上tag 如 nginx:xxx  默认为latest
      # 然后访问宿主主机地址+8800端口
      # pull到的镜像肯定有很多需要修改的地方,比如配置文件等或者要自己增加些什么玩意儿进去
      sudo docker exec -it 54d26bbce3d6 /bin/bash
      # 通过exec命令进入到容器内部进行操作, 其中字符串部分可以是容器id或容器名字
      # 进入之后就和操作新的系统一样,操作完成之后输入exit退出
      # 那么问题又来了, 进入容器内部并修改了东西后,怎么生成新的镜像供下次直接使用
      sudo docker commit nginx_huang huang/nginx:v1.0
        nginx_huang 表示我们刚修改的容器名字或者id
          huang/nginx:v1.0 为保存的镜像名字 :后面为tag
      
      # 刚刚commit的镜像仅仅是保存在本地的,如果要提交到网络上供其他人pull 使用呢? 如 https://cloud.docker.com/
      # 1.在https://cloud.docker.com/上注册一个账号
      # 2.提交本地镜像到https://cloud.docker.com/上去
      # 这样别人就可以通过docker pull xiaochangwei/nginx:v1.0 来获取并使用这个镜像了
      sudo docker commit nginx_huang huang/nginx:v1.0 镜像名里面包含了 我注册的账户名,这里需要一致,否则无法push
      
      # 到这里镜像怎么获取,查看,启动,编辑,保存,提交 容器查看 都知道了,但是怎么停止、启动、删除容器呢
      # 1.通过 sudo docker ps -a查看存在的容器信息
      # 2.通过 sudo docker start/stop/restart xxx 来启动、停止、重启指定的容器
      # 2.通过 sudo docker rm xxx 指定容器名或者容器id来删除,删除前请先停止容器,保证在非运行状态
      # 同样镜像的删除按如下操作
      # 1.通过sudo docker images 列出所有镜像
      # 2.通过sudo docker rmi xxx 来删除指定的镜像,镜像存在依赖关系,先删除最下层,最后删除顶层,建议根据镜像名字来删除

       

    6. 你平时是怎么去debug你的代码的?比如说有些代码是第一次写,你不知道你写的是不是对的,一但出现了问题,你要怎么去定位它,检测它?
      # 1.操作步骤:
      # 1-1.添加断点:直接在标记处点击鼠标左键即可。(删除断点只需再点击断点处即可)
      def add(x, y):
          z = x + y
          return z
      
      def sub(x, y):
          z = x - y
          return z
      
      def debug_test():           # 点击左侧,添加断点
          a = 10
          b = 5
          Sum = add(a, b)
          Sub = sub(a, b)
          print(Sum)
          print(Sub)
      
      if __name__ == "__main__":
          debug_test()
      
      # 1-2.Debug下运行代码:七星瓢虫shift + F9
      # 1-3.按照所需调试进行代码调试。Debug的调试方式如下所示:
      # 分别为:
      # 1.show execution point (F10)  显示当前所有断点
      # 2.step over(F8)  单步调试(若函数A内存在子函数a时,不会进入子函数a内执行单步调试,而是把子函数a当作一个整体,一步执行。)
      def add(x, y):
          z = x + y
          return z
      
      def sub(x, y):
          z = x - y
          return z
      
      def debug_test():           # 3 # 断点处
          a = 10                  # 4
          b = 5                   # 5
          Sum = add(a, b)         # 6
          Sub = sub(a, b)         # 7
          print(Sum)              # 8
          print(Sub)              # 9
      
      if __name__ == "__main__":  # 1
          debug_test()            # 2 # 10
      
      # 4.step into my code(Alt + Shift +F7) 执行下一行但忽略libraries(导入库的语句)(目前感觉没什么用)
      def add(x, y):
          z = x + y               # 7
          return z                # 8
      
      def sub(x, y):
          z = x - y               # 11
          return z                # 12
      
      def debug_test():           # 3 # 断点处
          a = 10                  # 4
          b = 5                   # 5
          Sum = add(a, b)         # 9
          Sub = sub(a, b)         # 13
          print(Sum)              # 14
          print(Sub)              # 15
      
      if __name__ == "__main__":  # 1
          debug_test()            # 2 # 16
      # 5.force step into(Alt + Shift +F7) 执行下一行忽略lib和构造对象等  (目前感觉没什么用)
      # 6.step out(Shift+F8)当目前执行在子函数a中时,选择该调试操作可以直接跳出子函数a,而不用继续执行子函数a中的剩余代码。并返回上一层函数。
      # 7.run to cursor(Alt +F9) 直接跳到下一个断点
      # ---------------------
      # 作者:放下扳手&拿起键盘
      # 来源:CSDN
      # 原文:https://blog.csdn.net/william_hehe/article/details/80898031

       

    7. 你有多长时间的软件开发经验?
  3. 业务类:

    1. 你对电商的业务了解吗?

      # 电商项目用户部分:主要分为三大类——1、用户浏览商品 ,2、购买商品 ,3、管理订单
      # 电商项目管理部分:主要也为三大类——1、商品数据整合网站 ,2、接受用户信息数据存入后台(注册和管理),3、处理用户订单问题

       

    2. 我问你一个具体的电商的业务啊:电商在大多数领域中都是有库存的,我在下订单的时候,我的库存的变化,你知道吗?(我问的是你怎么去处理库存的变化?)因为客户下单的时候,有些是去减库存了,有些不减对吧?你的理解呢?

      # 电商项目用户部分:主要分为三大类——1、用户浏览商品 ,2、购买商品 ,3、管理订单
      # 电商项目管理部分:主要也为三大类——1、商品数据整合网站 ,2、接受用户信息数据存入后台(注册和管理),3、处理用户订单问题
      
      #  一个简单的使用场景:一件商品的库存只有5件,同时A用户买了5个,B用户买了5个,都提交数据,照成库存不足的问题。
      #         逻辑:根据一般电商商品的模型类,生成订单一般包括订单类(Order)和订单详情类(DetailOrder),这两张表根据外键order_id 进行关联,所以是同生共死的关系,所以我们在这里用事务来控制。那么python如何解决库存问题呢?
      #         python 提供了2种方法解决该问题的问题:1,悲观锁;2,乐观锁
      #         悲观锁:在查询商品储存的时候加锁 select_for_update()  在发生事务的commit或者是事务的rollback时,自动释放该锁,这样其他用户就可以接着查询该商品。
      #         乐观锁:乐观锁不是真正的锁,在创建订单之前查询商品的库存,在创建订单详情表前,update更新查询数据,如果两次查询的库存量一样就创建详情表,并减去库存,否则,循环三次,如果都不一样,就发生rollback。
      #         使用场景:并发量高的时候使用悲观锁,缺点:加锁消耗资源
      #              并发量低的时候使用乐观锁,缺点:乐观锁循环耗费时间。
      # ---------------------
      # 作者:huangyali_python
      # 来源:CSDN
      # 原文:https://blog.csdn.net/huangyali_python/article/details/79511654

       

       

    3. 你事务的时候有没有出现死锁的情况?

      # 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁
      # 解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。
      from threading import Thread,Lock
      import time
      mutexA=Lock()
      mutexB=Lock()
      
      class MyThread(Thread):
          def run(self):
              self.func1()
              self.func2()
          def func1(self):
              mutexA.acquire()
              print('\033[41m%s 拿到A锁\033[0m' %self.name)
      
              mutexB.acquire()
              print('\033[42m%s 拿到B锁\033[0m' %self.name)
              mutexB.release()
      
              mutexA.release()
      
          def func2(self):
              mutexB.acquire()
              print('\033[43m%s 拿到B锁\033[0m' %self.name)
              time.sleep(2)
      
              mutexA.acquire()
              print('\033[44m%s 拿到A锁\033[0m' %self.name)
              mutexA.release()
      
              mutexB.release()
      
      if __name__ == '__main__':
          for i in range(10):
              t=MyThread()
              t.start()
      # 这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁,二者的区别是:递归锁可以连续acquire多次,而互斥锁只能acquire一次
      from threading import Thread,RLock
      import time
      
      mutexA=mutexB=RLock() #一个线程拿到锁,counter加1,该线程内又碰到加锁的情况,则counter继续加1,这期间所有其他线程都只能等待,等待该线程释放所有锁,即counter递减到0为止
      
      class MyThread(Thread):
          def run(self):
              self.func1()
              self.func2()
          def func1(self):
              mutexA.acquire()
              print('\033[41m%s 拿到A锁\033[0m' %self.name)
      
              mutexB.acquire()
              print('\033[42m%s 拿到B锁\033[0m' %self.name)
              mutexB.release()
      
              mutexA.release()
      
          def func2(self):
              mutexB.acquire()
              print('\033[43m%s 拿到B锁\033[0m' %self.name)
              time.sleep(2)
      
              mutexA.acquire()
              print('\033[44m%s 拿到A锁\033[0m' %self.name)
              mutexA.release()
      
              mutexB.release()
      
      if __name__ == '__main__':
          for i in range(10):
              t=MyThread()
              t.start()

       

    4. 你刚刚说到的下单之后的库存锁的问题?你是在下单的时候去扣库存,还是在支付完成了以后去扣?

      # 一、扣减库存的三种方案
      # (1)下单减库存
      #   用户下单时减库存
      #   优点:实时减库存,避免付款时因库存不足减库存的问题
      #   缺点:恶意买家大量下单,将库存用完,但是不付款,真正想买的人买不到
      # (2)付款减库存
      #   下单页面显示最新的库存,下单时不会立即减库存,而是等到支付时才会减库存。
      #   优点:防止恶意买家大量下单用光库存,避免下单减库存的缺点
      #   缺点:下单页面显示的库存数可能不是最新的库存数,而库存数用完后,下单页面的库存数没有刷新,出现下单数超过库存数,若支付的订单数超过库存数,则会出现支付失败。
      # (3)预扣库存
      #   下单页面显示最新的库存,下单后保留这个库存一段时间(比如10分钟),超过保留时间后,库存释放。若保留时间过后再支付,如果没有库存,则支付失败。例如:要求30分钟内支付订单。
      #   优点:结合下单减库存的优点,实时减库存,且缓解恶意买家大量下单的问题,保留时间内未支付,则释放库存。
      #   缺点:保留时间内,恶意买家大量下单将库存用完。并发量很高的时候,依然会出现下单数超过库存数。
      # 二、如何解决恶意买家下单的问题
      # 这里的恶意买家指短时间内大量下单,将库存用完的买家。
      # (1)限制用户下单数量
      #   优点:限制恶意买家下单
      #   缺点:用户想要多买几件,被限制了,会降低销售量
      # (2)标识恶意买家
      #   优点:卖家设定一个备用库存,当支付时,库存已用完,扣减备用库存数,这就是常见的补货场景
      #   缺点:因高并发场景下,数据可能存在不一致性的问题
      # 三、如何解决下单成功而支付失败(库存不足)的问题
      # (1)备用库存
      #   商品库存用完后,如果还有用户支付,直接扣减备用库存。
      #   优点:缓解部分用户支付失败的问题
      #   缺点:备用库存只能缓解问题,不能从根本上解决问题。另外备用库存针对普通商品可以,针对特殊商品这种库存少的,备用库存量也不会很大,还是会出现大量用户下单成功却因库存不足而支付失败的问题。
      # 四、如何解决高并发下库存超卖的场景
      # 库存超卖最简单的解释就是多成交了订单而发不了货。
      # 场景:
      # 用户A和B成功下单,在支付时扣减库存,当前库存数为10。因A和B查询库存时,都还有库存数,所以A和B都可以付款。
      # A和B同时支付,A和B支付完成后,可以看做两个请求回调后台系统扣减库存,有两个线程处理请求,两个线程查询出来的库存数 inventory=10,
      # 然后A线程更新最终库存数 lastInventory=inventory - 1 = 9,
      # B线程更新库存数 lastInventory=inventory - 1 = 9。
      # 而实际最终的库存应是8才对,这样就出现库存超卖的情况,而发不出货。
      # 那如何解决库存超卖的情况呢?
      # 1.SQL语句更新库存时,如果扣减库存后,库存数为负数,直接抛异常,利用事务的原子性进行自动回滚。
      # 2.利用SQL语句更新库存,防止库存为负数
      #  UPDATE [库存表] SET 库存数 - 1 WHERE 库存数 - 1 > 0
      #  如果影响条数大于1,则表示扣减库存成功,否则订单失败,并退款。
      # 五、秒杀场景下如何扣减库存
      # (1)下单减库存
      # 因秒杀场景下,大部分用户都是想直接购买商品的,可以直接用下单减库存。
      # 大量用户和恶意用户都是同时进行的,区别是正常用户会直接购买商品,恶意用户虽然在竞争抢购的名额,但是获取到的资格和普通用户一样,所以下单减库存在秒杀场景下,恶意用户下单并不能造成之前说的缺点。
      # 而且下单直接扣减库存,这个方案更简单,在第一步就扣减库存了。
      # (2)将库存放到redis缓存中
      #   查询缓存要比查询数据库快,所以将库存数放在缓存中,直接在缓存中扣减库存。然后在通过MQ异步完成数据库处理。
      # (3)使用量自增方式
      # 可以先增加已使用量,然后与设定的库存进行比较,如果超出,则将使用量减回去。
      #
      # 项目中用到了很多机制,但是没有总结出来,学习架构需要不断地总结。
      #
      # 六 第三方支付
      # 1 支付成功多次回调:把减库存放在微信支付的成功回调URL的方法里面。但是微信支付成功之后微信支付平台会发送8次请求到回调地址。这样的做法就会导致库存减少,一定要验证返回的编号是否已经完成扣减。

       

    5. 如果用户不支付,你的库存怎么办?(我还是没有听到你说,处理库存的点)

      # 设置支付时间,下单应该是锁定库存但是不减库存。如果你整个下单支付是队列方式的话,就支付完成之后立即减库存。超时就释放掉锁

       

    6. 如果支付失败了,你对库存有一个什么样的动作?

      # 支付完成后对库存进行更新,更新库存在事务中进行同时加锁,加的锁要避免堵塞,支付失败或者支付异常回滚,重新更新库存
      
      # 方案1:在下单就锁定库存
      #     优点:可以解决库存减扣问题
      #     缺点:体验差,如果只下单未付款,库存被锁定,让有意愿购买的用户无从下单,对销售业务有很大影响;
      # 
      # 方案2:支付后减扣库存
      #     优点:防止恶意下单,只要有足够的实际库存,随便多少意向客户下单
      #     缺点:下单页面显示的库存数可能不是最新的库存数,其他用户可能提示库存不足,可能出现超卖问题。
      # 
      # 方案3:调起支付界面前锁定库存
      # 
      #     优点:防止恶意下单,只要有足够的实际库存,随便多少意向客户下单
      #     缺点:体验差,有可能在支付时提示库存被其他用户锁定,提示库存不足
      # 
      # 方案4:下单占库存根据库存大小决定库存锁定时间
      # 
      #      库存充足下单占库存,设定库存最大占用时间,按库存大小限购数量按策略缩减库存占用时间
      # 
      #  
      # 
      #  
      # 
      # 具体以哪种方案为主还是要看公司的业务做决定
      # 
      # 
      #  
      # 
      # 下面主要讲解方案3 支付前锁定库存的的实现步骤,以下是使用到的关键表
      # 
      # -------------------------------------------------------------------------------------
      # 订单表
      # 订单唯一编号     库存锁定状态(1库存已锁定 2库存已释放 3库存已确认,库存减扣成功)
      # -------------------------------------------------------------------------------------
      # 订单详细表
      # 订单编号      商品id     购买数量
      # -------------------------------------------------------------------------------------
      # 商品库存表
      # 商品id     库存数量     实际锁定库存数量  预锁定库存数量   限购数量
      # -------------------------------------------------------------------------------------
      # 
      # A商品库存 1个
      # 
      # 
      # 用户1  下单1个
      # 用户2  下单1个
      # 
      # 
      # 业务场景及解决方式:
      # 1.支付前预占库存 :用户1和用户2可能同时点击支付按钮,此时对于商品锁定库存来说只能有一个用户会锁定A商品的库存,剩下一个肯定锁定失败,此时应该提示其中一个用户(库存可能不足,请稍后再试),这里更新库存减扣应该都有前置条件的或者说版本号
      # 
      # 2.限制支付时间,需要设置一个支付时间
      # 
      # (设置三方支付过期时间为30分钟)调起支付页面锁定库存30分钟,30分钟后还未支付则还原预减库存
      # 
      # 3.检测恶意下单用户加入到店铺黑名单
      # 
      # 4.加入限购
      # 
      # 5.优化方式
      # 另一个用户跳转到三方支付界面,
      # 如果此用户取消支付,客户端应该发送一条消息告诉服务端恢复库存锁定,
      # 如果此用户支付成功,客户端应该发送一条消息告诉服务端确认减扣库存,
      # 客户端可能因某种情况发送失败,此时要考虑使用定时任务恢复超过多久库存还处于(根据锁定状态)锁定中的订单商品库存,应该先调用支付系统关闭原有未完成支付的订单,然后再恢复商品锁定库存
      # 支付系统异步通知支付成功修改库存,此时根据库存锁定状态进行不同的业务处理(1库存已锁定 2库存已释放 3库存已确认,库存减扣成功)
      # --------------------- 
      # 作者:www.weixuehu.com 
      # 来源:CSDN 
      # 原文:https://blog.csdn.net/t_332741160/article/details/80340188 
      # 版权声明:本文为博主原创文章,转载请附上博文链接!

       

       

       

点赞