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 #
      b = 5 #
      Sum = add(a, b) #
      Sub = sub(a, b) #
      print(Sum) #
      print(Sub) # if __name__ == "__main__": #
      debug_test() # 2 # 10 # 4.step into my code(Alt + Shift +F7) 执行下一行但忽略libraries(导入库的语句)(目前感觉没什么用)
      def add(x, y):
      z = x + y #
      return z # def sub(x, y):
      z = x - y #
      return z # def debug_test(): # 3 # 断点处
      a = 10 #
      b = 5 #
      Sum = add(a, b) #
      Sub = sub(a, b) #
      print(Sum) #
      print(Sub) # if __name__ == "__main__": #
      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
      # 版权声明:本文为博主原创文章,转载请附上博文链接!

MyFirstDay_答案_1.**猫(自己整理)的更多相关文章

  1. javascript专业八级测试答案整理

    前几天社区的群里森破发了一个这样的链接: http://ourjs.com/detail/52fb82e13bd19c4814000001 做了一遍后突然对人生感到了迷茫,本着不能只有我一个人伤心的原 ...

  2. 跟着老猫来搞GO-容器(1)

    前期回顾 前面的一章主要和大家分享了GO语言的函数的定义,以及GO语言中的指针的简单用法,那么本章,老猫就和大家一起来学习一下GO语言中的容器. 数组 数组的定义 说到容器,大家有编程经验的肯定第一个 ...

  3. 【Java EE 学习 73】【数据采集系统第五天】【参与调查】【导航处理】【答案回显】【保存答案】

    一.参与调查的流程 单击导航栏上的“参与调查”按钮->EntrySurveyAction做出相应,找到所有的Survey对象并转发到显示所有survey对象的页面上供用户选择->用户单击其 ...

  4. Java并发编程面试题 Top 50 整理版

    本文在 Java线程面试题 Top 50的基础上,对部分答案进行进行了整理和补充,问题答案主要来自<Java编程思想(第四版)>,<Java并发编程实战>和一些优秀的博客,当然 ...

  5. 【javascript常见面试题】常见前端面试题及答案

    转自:http://www.cnblogs.com/syfwhu/p/4434132.html 前言 本文是在GitHub上看到一个大牛总结的前端常见面试题,很多问题问的都很好,很经典.很有代表性.上 ...

  6. LuoguP2115 [USACO14MAR]破坏Sabotage【二分答案】By cellur925

    本来是想找一道生成树的题做的...结果被洛咕的标签骗到了这题...结果是二分答案与生成树一点mao关系都没有.... 题目大意:给你一个序列,请你删去某一个$l~r$区间的值($2<=i< ...

  7. 也许你需要点实用的-Web前端笔试题

    之前发的一篇博客里没有附上答案,现在有空整理了下发出来,希望能帮助到正在找工作的你,还是那句话:技术只有自己真正理解了才是自己的东西,共勉. Web前端笔试题 Html+css 1.对WEB标准以及w ...

  8. 腾讯 pc端面试(2015.10.26)

    整个面试过程全部围绕着我在前一家公司做过的项目开始提问.因为这个项目是我主要负责的,所以面试官第一个问题是让我讲解了整个项目的框架结构.在对于项目的框架结构的讲解方面,大致条理还算清醒但是因为很少对做 ...

  9. YouKu iOS笔试题一

    序言 最近收到某某同学将去youku的iOS笔试题的邮件,希望笔者能整理一下,并提供参考答案.笔者决定整理出来,并分享给大家.当然,与此同时,也想看看youku的笔试题到底有多难,也考考自己有多少料吧 ...

随机推荐

  1. Html+CSS二周目--->常用概念

    学习css几乎俩周,来总结一下 对于初学者来说,有一些基本的概念是我们应当清楚的.掌握这些概念,可以帮助你更加有效的开发,大大提高开发效率. 1.盒子模型 2.浮动(float) 3.定位(posit ...

  2. intellijidea课程 intellijidea神器使用技巧 3-2 livetemplate

    创建livetemplate分组: ctrl shift a ==> live templates ==> + ==> templates group 创建livetemplate模 ...

  3. jQuery 判断文本输入框的事件

    1.实现以下需求: 输入框中输入内容,发表按钮变为蓝色背景,删除为空则变为原来的颜色 代码实现:通过判断event.target.value是否为空 2.input事件:文本输入框正在输入时生效  f ...

  4. vue监听input标签的value值方法

    <input id="materialSearch" type="text" @keyup.enter="search" @input ...

  5. 对数组排序进行"洗牌"(随机排序)

    这段代码在这里使用Fisher Yates洗牌算法给一个指定的数组进行洗牌(随机排序). function shuffle(arr) {     var i,        j,        tem ...

  6. The sixteenth day

    It is a against the law to drive without a driver's license 翻译: 没有驾照,开车是违法的 注意点: 1.It(连读)is; witout( ...

  7. vue-router配置

    首先在App.vue中 1.使用router-link组件来导航,通过‘to'属性指定链接,<router-link> 默认会被渲染成一个 `<a>` 标签 <route ...

  8. Android - 通过真实案例学习解内存泄漏问题,最终发现Android原生Bug

    作为一个Android新手小白,刚到新公司,最近的工作就是在学习解各类Bug.转型之初,面临各种新知识,会有压力,但是学习的过程是快乐的. 上周刚遇上一类bug,就是应用的内存泄漏问题.最终通过前辈的 ...

  9. 使用ABAP(ADBC)和Java(JDBC)连接SAP HANA数据库

    在表DBCON里维护一条记录,指向HANA数据库.con_ENV里填入HANA数据库的主机名和端口号.如vmXXXX:30015 DATA: ls_new TYPE DBCON. ls_new-con ...

  10. ABI and ISA

    ABI定义了如何使用ISA. ISA定义了机器码的使用规则. http://www.delorie.com/gnu/docs/gmp/gmp_6.html ABI and ISA ABI (Appli ...