MyFirstDay_答案_1.**猫(自己整理)
1>***猫:
python基础类:
- 字符串反转的常用处理方式:
# 方法一:使用字符串切片
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)- 你说一下python中的迭代器、生成器、装饰器
# 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
# 在Python中,这种一边循环一边计算的机制,称为生成器:generator # 在代码运行期间动态增加功能的方式,称之为“装饰器”: Decorator # 生成器和迭代器的区别:
# 1、语法方面来讲:
# 生成器是用函数中yield语句来创建的。迭代器的创建首先跟函数无关,可以用iter([1,2])来创建。
# 2、使用方面来讲:
# 由于生成器是使用函数的方式创建的,所以生成器里面的所有过程都会被执行,但请注意生成器里面的过程只有在被next()调用或者for循环调用时,里面的过程才会被执行
- 你说一下python中的迭代器、生成器、装饰器
- 如果让你实现一个迭代器,你会怎么做
# 迭代器有两个基本的方法: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) - 怎么样获取一个生成器?
# 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
- 你有用过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() - 你有了解过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) 技能类:
- 你有用过git吗?
Git是分布式版本控制系统
集中式VS分布式:
集中式版本控制系统,版本库集中存放在中央服务器,必须要联网才能工作,没有历史版本库。
分布式版本控制系统,没有“中央服务器”,每个开发人员电脑上都有一个完整的版本库。
分布式优势:安全性更高,无需联网,若“中央服务器”故障,任何一个其他开发者本地都有最新的带历史记录的版本库。
主要区别在于历史版本库的存放,集中式历史版本只存在于中央服务器,而分布式中每个本地库都有历史记录存放。 - 你有合过代码吗?
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 - 你有布署过代码吗?
- 布署的步骤是怎样的?你是怎么样把你的代码放到服务器中的?
# 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
# 来源:简书
# 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。 - 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 来删除指定的镜像,镜像存在依赖关系,先删除最下层,最后删除顶层,建议根据镜像名字来删除 - 你平时是怎么去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 - 你有多长时间的软件开发经验?
- 你有用过git吗?
业务类:
你对电商的业务了解吗?
# 电商项目用户部分:主要分为三大类——1、用户浏览商品 ,2、购买商品 ,3、管理订单
# 电商项目管理部分:主要也为三大类——1、商品数据整合网站 ,2、接受用户信息数据存入后台(注册和管理),3、处理用户订单问题我问你一个具体的电商的业务啊:电商在大多数领域中都是有库存的,我在下订单的时候,我的库存的变化,你知道吗?(我问的是你怎么去处理库存的变化?)因为客户下单的时候,有些是去减库存了,有些不减对吧?你的理解呢?
# 电商项目用户部分:主要分为三大类——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你事务的时候有没有出现死锁的情况?
# 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁
# 解决方法,递归锁,在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()你刚刚说到的下单之后的库存锁的问题?你是在下单的时候去扣库存,还是在支付完成了以后去扣?
# 一、扣减库存的三种方案
# (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次请求到回调地址。这样的做法就会导致库存减少,一定要验证返回的编号是否已经完成扣减。如果用户不支付,你的库存怎么办?(我还是没有听到你说,处理库存的点)
# 设置支付时间,下单应该是锁定库存但是不减库存。如果你整个下单支付是队列方式的话,就支付完成之后立即减库存。超时就释放掉锁
如果支付失败了,你对库存有一个什么样的动作?
# 支付完成后对库存进行更新,更新库存在事务中进行同时加锁,加的锁要避免堵塞,支付失败或者支付异常回滚,重新更新库存 # 方案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.**猫(自己整理)的更多相关文章
- javascript专业八级测试答案整理
前几天社区的群里森破发了一个这样的链接: http://ourjs.com/detail/52fb82e13bd19c4814000001 做了一遍后突然对人生感到了迷茫,本着不能只有我一个人伤心的原 ...
- 跟着老猫来搞GO-容器(1)
前期回顾 前面的一章主要和大家分享了GO语言的函数的定义,以及GO语言中的指针的简单用法,那么本章,老猫就和大家一起来学习一下GO语言中的容器. 数组 数组的定义 说到容器,大家有编程经验的肯定第一个 ...
- 【Java EE 学习 73】【数据采集系统第五天】【参与调查】【导航处理】【答案回显】【保存答案】
一.参与调查的流程 单击导航栏上的“参与调查”按钮->EntrySurveyAction做出相应,找到所有的Survey对象并转发到显示所有survey对象的页面上供用户选择->用户单击其 ...
- Java并发编程面试题 Top 50 整理版
本文在 Java线程面试题 Top 50的基础上,对部分答案进行进行了整理和补充,问题答案主要来自<Java编程思想(第四版)>,<Java并发编程实战>和一些优秀的博客,当然 ...
- 【javascript常见面试题】常见前端面试题及答案
转自:http://www.cnblogs.com/syfwhu/p/4434132.html 前言 本文是在GitHub上看到一个大牛总结的前端常见面试题,很多问题问的都很好,很经典.很有代表性.上 ...
- LuoguP2115 [USACO14MAR]破坏Sabotage【二分答案】By cellur925
本来是想找一道生成树的题做的...结果被洛咕的标签骗到了这题...结果是二分答案与生成树一点mao关系都没有.... 题目大意:给你一个序列,请你删去某一个$l~r$区间的值($2<=i< ...
- 也许你需要点实用的-Web前端笔试题
之前发的一篇博客里没有附上答案,现在有空整理了下发出来,希望能帮助到正在找工作的你,还是那句话:技术只有自己真正理解了才是自己的东西,共勉. Web前端笔试题 Html+css 1.对WEB标准以及w ...
- 腾讯 pc端面试(2015.10.26)
整个面试过程全部围绕着我在前一家公司做过的项目开始提问.因为这个项目是我主要负责的,所以面试官第一个问题是让我讲解了整个项目的框架结构.在对于项目的框架结构的讲解方面,大致条理还算清醒但是因为很少对做 ...
- YouKu iOS笔试题一
序言 最近收到某某同学将去youku的iOS笔试题的邮件,希望笔者能整理一下,并提供参考答案.笔者决定整理出来,并分享给大家.当然,与此同时,也想看看youku的笔试题到底有多难,也考考自己有多少料吧 ...
随机推荐
- Html+CSS二周目--->常用概念
学习css几乎俩周,来总结一下 对于初学者来说,有一些基本的概念是我们应当清楚的.掌握这些概念,可以帮助你更加有效的开发,大大提高开发效率. 1.盒子模型 2.浮动(float) 3.定位(posit ...
- intellijidea课程 intellijidea神器使用技巧 3-2 livetemplate
创建livetemplate分组: ctrl shift a ==> live templates ==> + ==> templates group 创建livetemplate模 ...
- jQuery 判断文本输入框的事件
1.实现以下需求: 输入框中输入内容,发表按钮变为蓝色背景,删除为空则变为原来的颜色 代码实现:通过判断event.target.value是否为空 2.input事件:文本输入框正在输入时生效 f ...
- vue监听input标签的value值方法
<input id="materialSearch" type="text" @keyup.enter="search" @input ...
- 对数组排序进行"洗牌"(随机排序)
这段代码在这里使用Fisher Yates洗牌算法给一个指定的数组进行洗牌(随机排序). function shuffle(arr) { var i, j, tem ...
- The sixteenth day
It is a against the law to drive without a driver's license 翻译: 没有驾照,开车是违法的 注意点: 1.It(连读)is; witout( ...
- vue-router配置
首先在App.vue中 1.使用router-link组件来导航,通过‘to'属性指定链接,<router-link> 默认会被渲染成一个 `<a>` 标签 <route ...
- Android - 通过真实案例学习解内存泄漏问题,最终发现Android原生Bug
作为一个Android新手小白,刚到新公司,最近的工作就是在学习解各类Bug.转型之初,面临各种新知识,会有压力,但是学习的过程是快乐的. 上周刚遇上一类bug,就是应用的内存泄漏问题.最终通过前辈的 ...
- 使用ABAP(ADBC)和Java(JDBC)连接SAP HANA数据库
在表DBCON里维护一条记录,指向HANA数据库.con_ENV里填入HANA数据库的主机名和端口号.如vmXXXX:30015 DATA: ls_new TYPE DBCON. ls_new-con ...
- ABI and ISA
ABI定义了如何使用ISA. ISA定义了机器码的使用规则. http://www.delorie.com/gnu/docs/gmp/gmp_6.html ABI and ISA ABI (Appli ...