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

来源:https://www.cnblogs.com/wangxue533/archive/2019/04/08/10626558.html
-Advertisement-
Play Games

1>***貓: python基礎類: 技能類: 業務類: 你對電商的業務瞭解嗎? 我問你一個具體的電商的業務啊:電商在大多數領域中都是有庫存的,我在下訂單的時候,我的庫存的變化,你知道嗎?(我問的是你怎麼去處理庫存的變化?)因為客戶下單的時候,有些是去減庫存了,有些不減對吧?你的理解呢? 你事務的時 ...


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 [email protected]::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 
      #	   
      
      
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前提 vue在前端技術中使用越來越多,也成為了主流框架,花點時間稍微瞭解下vue-cli、vue-router結合element-ui的使用。本人使用的是windows系統,後續介紹以windows7系統為例。 1.安裝vue-cli 首先保證自己電腦上已經安裝過nodejs,是否安裝打開cmd,輸 ...
  • 本文將介紹如何使用Docker Compose搭建Istio。Istio號稱支持多種平臺(不僅僅Kubernetes)。然而,官網上非基於Kubernetes的教程仿佛不是親兒子,寫得非常隨便,不僅缺了一些內容,而且還有坑。本文希望能補實這些內容。我認為在學習Istio的過程中,相比於Kuberne ...
  • 工廠方法模式概述 工廠方法模式是為了彌補簡單工廠模式的不足並且繼承它的優點而延生出的一種設計模式,屬於GoF中的一種。它能更好的符合開閉原則的要求。 舉個例子:大眾汽車公司想必大家都不陌生,它旗下也有不少汽車品牌。大眾汽車公司就好比一個汽車工廠,負責生產和銷售汽車。它可以為客戶提供一個客戶需要的汽車 ...
  • 1.上傳視頻信息的jsp頁面uploadVideo.jsp <body background="image/bk_hero.jpg"><div id="upld" style="height:300px;width:300px;margin-left: 300px;margin-top: 100px ...
  • 後臺servlet設置 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method=reque ...
  • 清明節和朋友去被抖音帶火的一個餐廳,下午兩點鐘取晚上的號,前面已經有十幾桌了,四點半餐廳開始正式營業,等輪到我們已經近八點了。餐廳分為幾個區域,只有最火的區域(在小船上)需要排號,其他區域基本上是隨到隨吃的,最冷清的區域幾乎都沒什麼人。菜的價格異常的貴,味道也並不好。最後送出兩張圖: 好了,進入今天 ...
  • 簡介 當你的程式不能正常運行的時候,Python會在控制台列印一段提醒,告訴你一個錯誤,這個錯誤就是異常。 錯誤 我在控制台寫了一段無效的代碼,將print()的括弧去掉,在執行這條語句的時候,系統提示語法錯誤,無效的語句(我百度翻譯的)。這就是錯誤處理器所作的工作。 再換一種方式寫錯誤: 在程式獲 ...
  • 1.防止用戶沒有登錄即可訪問其他頁面 1.1>從session中判斷用戶是否登陸 ServletActionContext.getRequest().getSession();以此為依據是否放行 2.註冊自定義攔截器 3.設置預設攔截器 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...