举个例子:
A想要从自己的帐户中转1000块钱到B的帐户里。那个从A开始转帐,到转帐结束的这一个过程,称之为一个事务。在这个事务里,要做如下操作:
- 1. 从A的帐户中减去1000块钱。如果A的帐户原来有3000块钱,现在就变成2000块钱了。
- 2. 在B的帐户里加1000块钱。如果B的帐户如果原来有2000块钱,现在则变成3000块钱了。
如果在A的帐户已经减去了1000块钱的时候,忽然发生了意外,比如停电什么的,导致转帐事务意外终止了,而此时B的帐户里还没有增加1000块钱。那么,我们称这个操作失败了,要进行回滚。回滚就是回到事务开始之前的状态,也就是回到A的帐户还没减1000块的状态,B的帐户的原来的状态。此时A的帐户仍然有3000块,B的帐户仍然有2000块。
我们把这种要么一起成功(A帐户成功减少1000,同时B帐户成功增加1000),要么一起失败(A帐户回到原来状态,B帐户也回到原来状态)的操作叫原子性操作。
如果把一个事务可看作是一个程序,它要么完整的被执行,要么完全不执行。这种特性就叫原子性。
Django提供了一种简单的API去控制数据库的事务交易...原子操作用来定义数据库事务的属性。原子操作允许我们在数据库保证的前提下,创建一堆代码。如果这些代码被成功的执行,所对应的改变也会提交到数据库中。如果有异常发生,那么操作就会回滚。”
用法和上例一致,可以采用装饰器用法或代码块用法,推荐代码块。
def index(request):
try:
with transaction.atomic():
work2()
except Exception:
pass
具体事例:
def post(self,request):
if not request.user.is_authenticated():
# 如果没有登录则跳转到登陆界面
return redirect_to_login('request.get_full_path')
# 通过getlist获取对应的checkbox类型的value,保存一个list类型的数据
# 通过checkbox来获取提交的商品,勾选就提交,不勾选不提交
#checkbox的name='cart_by_goods_id'
cart_by_goods_ids = request.POST.getlist('cart_by_goods_id')
#通过in_bulk,传入对应的id集合,则会返回对应的对象集合字典
shopcarts = ShopCart.objects.in_bulk(id_list=cart_by_goods_ids)
#数据验证,给多少id就要返回多少数据,否则说明购物车数据异常
#assert用法:如果assert返回false则终止程序
assert len(shopcarts.keys()) == len(cart_by_goods_ids)
try:
# 提交订单时实例化一个订单
# 创建订单,要么全部成功,要么全部失败,因为该业务是一个原子操作
# 使用transaction.atomic做事务,保证所有数据库操作保持原子性
# 将需要进行原子操作的代码放到with transaction.atomic():里面
with transaction.atomic():
ordermain = OrderMain(uuid=uuid.uuid4(),user=request.user,total=0)
ordermain.save()
#遍历出所有商品
total = 0
for shopcart in shopcarts.values():
orderdetail = OrderDetail()
orderdetail.order = ordermain
orderdetail.goods_info = shopcart.goodsinfo
orderdetail.goods_price = float(shopcart.goodsinfo.price)
if shopcart.buy_num > shopcart.goodsinfo.stock:
message = u'%s库存不足'% shopcart.goodsinfo.name
raise StockException,message
orderdetail.count = shopcart.buy_num
orderdetail.goods_total = float(shopcart.goodsinfo.price * shopcart.buy_num)
total += orderdetail.goods_total
orderdetail.save()
#将购物车保存到订单后字典中要删除对应的购物车
ShopCart.objects.filter(id=shopcart.id).delete()
ordermain.total = total
ordermain.save()
except StockException,e:
message = e
cart_infos = ShopCart.objects.filter(user=request.user)
return render(request,'shop_cart/cart.html',locals())
#成功就跳转订单详情展示
return redirect(reverse('shop_order:show_order',kwargs={'oid':ordermain.id}))