Python开发入门与实战10-事务
1. 事务
本章我们将通过一个例子来简要的说明“事务”,这个开发实战里经常遇到的名词。事务是如何体现在一个具体的业务和系统的实现里。
事务是通过将一组相关操作组合为一个,要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。事务具有4个特性:原子性、一致性、隔离性、持久性。业务事务就是完成具体业务操作后,形成的业务结果;数据库事务是数据库产品根据事务的特性实现的相关功能,数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行,也可以理解成事务在数据库管理系统的实现。Django作为可以支持数据持久化的框架,也要支持的事务特性机制。
前面章节,我们描述的入库与库存的例子,现实世界的业务事务入库场景是这样,物品入库就是仓库管理员拿着新购进的物品,摆放到相应的货位上,同时更新库存登记簿,更新(增加)该物品的库存数据量,如果过程中仓库管理员忘记更新库存登记簿的库存数据将导致该物品的账目数据量与该物品的仓库货位实际库存数据量不一致,从而导致混乱。
库存管理业务系统依据这一业务逻辑规则,我们简化设计了2张表,入库单表和物品库存表来满足这一业务要求。业务系统的处理逻辑就是当新增的入库单数据保存到数据库入库表后,就必须更新库存表、该物品的库存数据,这个过程如果出现某种意外,如更新库存数据失败,就必须同时回滚、入库表的相应操作。这就是事务特性要求的:要么同时成功要么同时失败。
本章节将继续以入库事务这个例子来说明我们在系统中如何设计和实现事务的要求。
1.1. 入库操作流程
按照我们前面设计的入库单业务,每次入库单,其过程至少包括以下二个步数据库操作:
一、保存入库单信息到数据库;
二、更新入库单物品的当前库存信息,库存数量=当前库存数量+入库数量。
正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新。但是,如果在这一系列过程中任何一个环节出了差错,例如在更新物品库存信息时发生异常导致交易失败。一旦交易失败,数据库中所有信息都必须保持交易前的状态不变,比如最后一步更新物品库存信息时失败而导致交易失败,那么必须保证这笔失败的交易不影响数据库的状态--库存信息没有被更新、入库单也没有提交成功。
1.1. 现在我们修改我们的代码来实现新增入库单时更新我们的库存信息
我们在AddInStockBill函数中增加如下代码来更新当前库存信息:
def AddInStockBill(request):
if request.method == 'POST':
form = InStockBillForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
inStockBill = InStockBill()
inStockBill.InStockBillCode = cd['InStockBillCode']
inStockBill.InStockDate = cd['InStockDate']
inStockBill.Amount = cd['Amount']
inStockBill.Operator = cd['Operator']
inStockBill.Item = cd['Item'] inventorys = inStockBill.Item.inventory_set.all()
currentInventory = Inventory()
if (inventorys.count()==0):
currentInventory.Item = inStockBill.Item
currentInventory.Amount = inStockBill.Amount
else:
#这里假定只有一个物料,后面我们会根据进程重构代码
currentInventory = inventorys[0]
currentInventory.Amount = currentInventory.Amount + inStockBill.Amount currentInventory.save() #更新库存
inStockBill.save() #保存入库单数据
return HttpResponseRedirect('/success/')
else:
form = InStockBillForm()
return render_to_response('InStockAdd.html',{'form': form}
,context_instance = RequestContext(request))
我们现在新增一条入库单来测试我们的入库事务是否实现了更新库存信息。

提交成功后,我们查看数据库会发现库存表和入库单表数据都保存成功了,如下图:


1.1. 事务失败
我们数据库inventory_instockbill表中增加一个非空字段remark来模拟,来模拟更新库存后,系统在提交入库单据时出现了异常系统返回失败了,由于model没有同步这个字段,入库单model提交时会引发错误,这时根据事务的规则,库存的更新应该会回滚,就是库存表数据不更新,入库单表没有新的入库单数据。如下图:

运行的结果,库存表库存数量更新为25,但是入库单据没有保存成功,也就是意味着系统运行的结果与业务事务是不符合的,丢失的入库单据已经导致库存数量发生变化,我们需要用一定的机制来保证业务事务满足要求。如下图:

1.2. Django事务处理
默认情况下,在Django中事务是自动提交的。当我们运行Django内置的模板修改函数时,例如调用model.save()或model.delete()时,事务将被立即提交。这种机制和数据库的自动提交事务机制类似。记住这里没有默认的回滚机制,要解决刚才的场景我们须引入Django的数据库事务控制类django.db.transaction
1.2.1. 在View中实现事务控制
如果想在更细粒度的条件下(例如在一个view函数中)控制事务,我们可以使用django.db.transaction。有两种用法:
1. 使用装饰器
from django.db import transaction @transaction.commit_on_success
def viewfunc(request):
# ... # this code executes inside a transaction # ...
2. 使用context manager
from django.db import transaction def viewfunc(request):
# ... # this code executes using default transaction management # ... with transaction.commit_on_success():
# ... # this code executes inside a transaction # ...
1.2.2. 标识使用方法
1. autocommit
使用autocommit装饰器可以将view函数中的事务还原成Django默认的自动提交模式,无视全局事务的设置。
from django.db import transaction @transaction.autocommit
def viewfunc(request): ....
2. commit_on_success()
顾名思义,view函数成功则提交事务,否则回滚。用法同上。
3. commit_manually()
告诉Django我们将自己控制函数中的事务处理。并且要注意,如果在视图函数中改变了数据库的数据并且没有调用commit()或rollback(),那么将抛出TransactionManagementError异常。
from django.db import transaction @transaction.commit_manually
def viewfunc(request): ...
# You can commit/rollback however and whenever you want
transaction.commit()
... # But you've got to remember to do it yourself! try:
... except: transaction.rollback() else: transaction.commit()
1.3. AddInStockBill增加事务标识
from django.db import transaction @transaction.commit_on_success
def AddInStockBill(request):
1.4. 事务测试
现在我们重新执行前面事务失败的例子,来看系统运行的结果是否满足事务的基本要求。

提交后系统报错,这我们也会发现数据库intentory表,提交的数据回滚了,库存数量没有更新。入库单业务实现了正确的业务事务,避免错误、混乱的数据提交到数据库中。
1.5. 小结
本章节我们用入库的业务例子来阐述如何运行Django的事务机制,以满足业务事务的要求,例子中我们采用了commit_on_success(),在实际应用中可以根据自己的业务逻辑采用不同的事务标识。
下一个章我们将继续以入库单的例子参数如何编写支持单元测试的代码例子。
Python开发入门与实战10-事务的更多相关文章
- Python开发入门与实战1-开发环境
1.搭建Python Django开发环境 1.1.Python运行环境安装 Python官网:http://www.python.org/ Python最新源码,二进制文档,新闻资讯等可以在Pyth ...
- Python开发入门与实战8-基于Java的集成开发环境
8. 基于Java的Python的集成开发环境 目前为止我们所有的代码和例子都是通过Notepad文本编辑器来实现的,实际项目开发中这种编码模式效率较低(大虾除外),使用IDE集成开发环境常常大幅度的 ...
- Python开发入门与实战5-django模型
5.Django模型 在当今的Web 应用中,主观逻辑经常牵涉到与数据库的交互,数据库驱动网站.在后台连接数据库服务器,从中取出一些数据,然后在 Web 页面用各种各样的格式展示这些数据.这个网站也可 ...
- Python开发入门与实战17-新浪云部署
17. 新浪云部署 上一章节我们介绍了如何在本地windows服务器部署python django的网站,本章我们简要说明一下如何把python django工程部署到云服务上. 本章章节我们描述如何 ...
- Python开发入门与实战13-基于模板的界面
13. 基于模板的界面 本章我们将继续基于库存的简单例子来阐述如何在python django中体现MVC的架构,根据djangobook说明: M:数据存取部分,由django数据库层处理,本章要讲 ...
- Python开发入门与实战12-业务逻辑层
12. Biz业务层 前面的章节我们把大量的业务函数都放在了views.py里,按照目前这一的写法,当我们编写的系统复杂较高时,我们的views.py将会越来越复杂,大量的业务函数包含其中使其成为一个 ...
- Python开发入门与实战7-Django Form
7. Django Form 7.1. Form表单 Django带有一个form库,称为django.forms,这个库可以处理上一章提到的包括HTML表单的自动生成以及数据验证. 我们在inven ...
- Python开发入门与实战6-表单
6. 表单 从简朴的单个搜索框,到常见的Blog评论提交表单,再到复杂的自定义数据输入接口,HTML表单一直是交互性网站的重要交互手段.本章介绍如何用Django如何对用户通过表单提交的数据进行访问. ...
- Python开发入门与实战2-第一个Django项目
2.第一个Django项目 上一章节我们完成了python,django和数据库等运行环境的安装,现在我们来创建第一个django project吧,迈出使用django开发应用的第一步. 2.1.创 ...
随机推荐
- Java判断访问设备为手机、微信、PC工具类
package com.lwj.util; import javax.servlet.http.HttpServletRequest; /** * 判断访问设备为PC或者手机--工具类 * * @de ...
- 论Postgres的“已提交的而且 xmin’比当前事务的XID小的记录对当前事务才是可见的”
最近在网上看到这样一句话Postgres“已提交的而且 xmin 比当前事务的XID小的记录对当前事务才是可见的”.先不评断这句话的正确性:看下这句话的结构,因果关系: 按照此话的意思:要postgr ...
- [课程设计]Sprint Two 回顾与总结&发表评论&团队贡献分
[课程设计]Sprint Two 回顾与总结&发表评论&团队贡献分 ● 一.回顾与总结 (1)回顾 燃尽图: Sprint计划-流程图: milestones完成情况如下: (2)总结 ...
- 【转】malloc与free的底层实现
本文转自:http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201210975312473/ 如何查看进程发生缺页中断的次数? 用ps ...
- VIM 常用错误解决
1.option ‘omnifunc’ is not set 错误: vim7下Omni completion默认情况下是没有开启的,有时候自定义的vimrc文件会实现自动补齐,例如vim-autoc ...
- 【Python】我的Python学习笔记【2】【using Python 3】
... 1. 在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值, 所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便. 2. ...
- 从零开始学iPhone开发(1)——工具的使用
前提:已经具备了苹果电脑或者iMac,或者安装好了x86苹果而且已经联网. 苹果系统版本要求是:Max OS X Lion,或者 Mountain Lion 我们对iPhone进行使用的工具是XCod ...
- SSH服务器拒绝密码检测
这两天在配置Ubuntu 14.04的环境时,碰到一个典型的问题:在用xshell 连接Ubuntu时,显示"SSH服务器拒绝密码检测"的问题,在经过一系列配置修改后,最终怀疑是否 ...
- ShareSDK第三方登录代码
- (IBAction)YYSJBut:(UIButton *)sender{ if (sender.tag == 7) { [self AuthLogin:SSDKPlat ...
- [转](三)unity4.6Ugui中文教程文档-------概要-UGUI Basic Layout
大家好,我是孙广东. 转载请注明出处:http://write.blog.csdn.net/postedit/38922399 更全的内容请看我的游戏蛮牛地址:http://www.unityma ...