最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Python的Django框架實(shí)現(xiàn)事務(wù)交易管理的教程

 更新時(shí)間:2015年04月20日 10:21:06   投稿:goldensun  
這篇文章主要介紹了使用Python的Django框架實(shí)現(xiàn)事務(wù)交易管理的教程,針對(duì)數(shù)據(jù)庫(kù)的事務(wù)行為進(jìn)行一系列操作,要的朋友可以參考下

 如果你花費(fèi)了很多的時(shí)間去進(jìn)行Django數(shù)據(jù)庫(kù)事務(wù)處理的話,你將會(huì)了解到這是讓人暈頭轉(zhuǎn)向的。

在過(guò)去,只是提供了簡(jiǎn)單的基礎(chǔ)文檔,要想清楚知道它是怎么使用的,還必須要通過(guò)創(chuàng)建和執(zhí)行Django的事務(wù)處理。

這里有眾多的Django事務(wù)處理的名詞,例如:commit_on_success , commit_manually , commit_unless_maneged,rollback_unless_managed,enter_transaction_management,leace_transaction_management,這些只是其中的一部分而已。

最讓人感到幸運(yùn)的是,Django 1.6版本發(fā)布后?,F(xiàn)在你可以緊緊使用幾個(gè)函數(shù)就可以實(shí)現(xiàn)事務(wù)處理了,在我們進(jìn)入學(xué)習(xí)這些函數(shù)的幾秒之前。首先,我們要明確下面這些問(wèn)題:

  •     什么是事務(wù)處理呢?
  •     Django 1.6中的出現(xiàn)了那些新的事物處理優(yōu)先權(quán)?

在進(jìn)入“要怎么才是Django 1.6版本中正確的事務(wù)處理”之前,請(qǐng)先了解一下下面的詳細(xì)案例:

    帶狀案例

    事務(wù)

  •             推薦的方式
  •             使用分隔符
  •             每一個(gè)HTTP請(qǐng)求事務(wù)

    保存點(diǎn)

    嵌套的事務(wù)


事務(wù)是什么?

根據(jù)SQL-92所說(shuō),"一個(gè)SQL事務(wù)(有時(shí)簡(jiǎn)稱為事務(wù))是一個(gè)可以原子性恢復(fù)的SQL語(yǔ)句執(zhí)行序列"。換句話說(shuō),所有的SQL語(yǔ)句一起執(zhí)行和提交。同樣的,當(dāng)回滾時(shí),所有語(yǔ)句也一并回滾。

例如:
 

# START
note = Note(title="my first note", text="Yay!")
note = Note(title="my second note", text="Whee!")
address1.save()
address2.save()
# COMMIT

所以一個(gè)事務(wù)是 數(shù)據(jù)庫(kù)中單個(gè)的工作單元。它是由一個(gè)start transaction開始和一個(gè)commit或者顯式的rollback結(jié)束。

Django 1.6之前的事務(wù)管理有什么問(wèn)題?

為了完整地回答這個(gè)問(wèn)題,我們必須闡述一下事務(wù)在數(shù)據(jù)庫(kù)、客戶端以及Django中是如何處理的。

數(shù)據(jù)庫(kù)

數(shù)據(jù)庫(kù)中的每一條語(yǔ)句都運(yùn)行在一個(gè)事務(wù)中,這個(gè)事務(wù)甚至可以只包含一條語(yǔ)句。

幾乎所有的數(shù)據(jù)庫(kù)都有一個(gè)AUTOCOMMIT設(shè)置,通常它被默認(rèn)設(shè)置為True。AUTOCOMMIT將所有語(yǔ)句包裝到一個(gè)事務(wù)里,只要語(yǔ)句成功執(zhí)行,這個(gè)事務(wù)就立即被提交。當(dāng)然你也可以手動(dòng)調(diào)用START_TRANSACTION,它會(huì)暫時(shí)將AUTOCOMMIT掛起,直到你調(diào)用COMMIT_TRANSACTION或者ROLLBACK。

然后,這種方式將會(huì)使AUTOCOMMIT設(shè)置的作用于每條語(yǔ)句后的隱式提交失效。


然而,有諸如像sqlite3和mysqldb的python客戶端庫(kù),它允許python程序與數(shù)據(jù)庫(kù)本身相連接。這些庫(kù)遵循一套如何訪問(wèn)與查詢數(shù)據(jù)庫(kù)的標(biāo)準(zhǔn)。該DB API 2.0標(biāo)準(zhǔn),被描述在PEP 249之中。雖然它可能讓人閱讀稍干一些。一個(gè)重要帶走的是,在PEP 249狀態(tài)之中,默認(rèn)數(shù)據(jù)庫(kù)應(yīng)該關(guān)閉自動(dòng)提交功能。

這明顯與數(shù)據(jù)庫(kù)內(nèi)發(fā)生了什么矛盾沖突:

  •     數(shù)據(jù)庫(kù)語(yǔ)句總是要在一個(gè)事務(wù)中運(yùn)行。此數(shù)據(jù)庫(kù)一般會(huì)為你打開自動(dòng)提交功能。
  •     不過(guò),根據(jù)PEP 249,這不應(yīng)該發(fā)生。
  •     客戶端庫(kù)必須反映在數(shù)據(jù)庫(kù)之中發(fā)生了什么?但由于他們不允許默認(rèn)打開自動(dòng)提交功能。他們只是簡(jiǎn)單地在一個(gè)事務(wù)中包裹sql語(yǔ)句。就像數(shù)據(jù)庫(kù)。

好啦,在我身邊呆久一些吧。

 

Django

進(jìn)入Django,Django也有關(guān)于事務(wù)處理的話要說(shuō)。在Django 1.5和更早的版本。當(dāng)你寫數(shù)據(jù)到數(shù)據(jù)庫(kù)時(shí),Django基本上是運(yùn)行一個(gè)開放的事務(wù)和自動(dòng)提交該事務(wù)功能。所以每次你所稱謂的像諸如model.save() 或者model.update()的東西,Django生成相應(yīng)的sql語(yǔ)句,并提交該事務(wù)。

也有在Django 1.5和更早的版本,它是建議你使用TransactionMiddleware綁定http請(qǐng)求事務(wù)。每個(gè)請(qǐng)求提供了一個(gè)事務(wù)。如果返回的響應(yīng)沒(méi)有異常,Django會(huì)提交此事務(wù)。但如果你的視圖功能拋出一個(gè)錯(cuò)誤,回滾將被調(diào)用。這實(shí)際上說(shuō)明,它關(guān)閉了自動(dòng)提交功能。如果你想要標(biāo)準(zhǔn)化,數(shù)據(jù)庫(kù)級(jí)別自動(dòng)提交風(fēng)格式的事務(wù)管理,你必須管理你自己的交易-通常是通過(guò)使用事務(wù)裝飾你的視圖功能,例如@transaction.commit_manually,或者@transaction.commit_on_success.

吸一口氣,或者兩口。


這意味著什么?

是啊,在那兒有許多事情要做,而事實(shí)證明,大多數(shù)開發(fā)者正需要這個(gè)標(biāo)準(zhǔn)數(shù)據(jù)庫(kù)級(jí)的自動(dòng)提交功能-有意義的事務(wù)往往是留在幕后處理的。做你自己的事,直到你需要手動(dòng)調(diào)整他們。

在Django 1.6版本之中,什么是正確關(guān)于事務(wù)管理呢?

現(xiàn)在,歡迎來(lái)到Django 1.6.盡力忘掉一切吧,我們只是談?wù)摱眩皇怯浀迷贒jango 1.6中,你可以使用數(shù)據(jù)庫(kù),需要時(shí)可以手動(dòng)自動(dòng)提交和管理事務(wù)。從本質(zhì)上來(lái)說(shuō),我們有一個(gè)更簡(jiǎn)單的模型,基本上是要把設(shè)計(jì)什么樣的數(shù)據(jù)庫(kù)擺在首位。

好啦!大功告成,讓我們寫代碼吧?

 

Stripe案例

下面,我們使用處理一個(gè)用戶注冊(cè)的例子,調(diào)用了Stripe來(lái)處理信用卡進(jìn)程。
 

def register(request):
  user = None
  if request.method == 'POST':
    form = UserForm(request.POST)
    if form.is_valid():
 
      customer = Customer.create("subscription",
       email = form.cleaned_data['email'],
       description = form.cleaned_data['name'],
       card = form.cleaned_data['stripe_token'],
       plan="gold",
      )
 
      cd = form.cleaned_data      
      try:
        user = User.create(cd['name'], cd['email'], cd['password'],
          cd['last_4_digits'])
 
        if customer:
          user.stripe_id = customer.id
          user.save()
        else:
          UnpaidUsers(email=cd['email']).save()
 
      except IntegrityError:
        form.addError(cd['email'] + ' is already a member')
      else:
        request.session['user'] = user.pk
        return HttpResponseRedirect('/')
 
  else:
   form = UserForm()
 
  return render_to_response(
    'register.html',
    {
     'form': form,
     'months': range(1, 12),
     'publishable': settings.STRIPE_PUBLISHABLE,
     'soon': soon(),
     'user': user,
     'years': range(2011, 2036),
    },
    context_instance=RequestContext(request)
  )

例子首先調(diào)用了Customer.create,實(shí)際上就是調(diào)用Stripe來(lái)處理信用卡進(jìn)程,然后我們創(chuàng)建一個(gè)新用戶。如果我們得到來(lái)自Stripe的響應(yīng),我們就用stripe_id更新新創(chuàng)建的用戶。如果我們沒(méi)有得到響應(yīng)(Stripe已關(guān)閉),我們將用新創(chuàng)建用戶的email向UnpaidUsers表增加一個(gè)新條目,這樣我們可以讓他們稍后重試他們信用卡信息。


思路是這樣的:如果Stripe沒(méi)有響應(yīng),用戶依然可以注冊(cè),然后開始使用我們的網(wǎng)站。我們將在稍后的時(shí)候讓用戶提供信用卡的信息。

“我明白這是一個(gè)特殊的例子,并且這也不是我想完成的功能的方式,但是它的目的是展示交易”

考慮交易,牢記住在Django1.6中提供了對(duì)于數(shù)據(jù)庫(kù)的“AUTOCOMMIT”功能。接下來(lái)看一下數(shù)據(jù)庫(kù)相關(guān)的代碼:
 

cd = form.cleaned_data
try:
  user = User.create(cd['name'], cd['email'], cd['password'], cd['last_4_digits'])
 
  if customer:
    user.stripe_id = customer.id
    user.save()
  else:
    UnpaidUsers(email=cd['email']).save()
 
except IntegrityError:

你能發(fā)現(xiàn)問(wèn)題了嗎?如果“UnpaidUsers(email=cd['email']).save()” 運(yùn)行失敗,會(huì)發(fā)生什么?

有一個(gè)用戶,注冊(cè)了系統(tǒng);然后系統(tǒng)認(rèn)為已經(jīng)核對(duì)過(guò)信用卡了。但是事實(shí)上,系統(tǒng)并沒(méi)有核對(duì)過(guò)。

我們僅僅想得到其中一種結(jié)果:

1.在數(shù)據(jù)庫(kù)中創(chuàng)建了用戶,并有了stripe_id

2.在數(shù)據(jù)庫(kù)中創(chuàng)建了用戶,但是沒(méi)有stripe_id。同時(shí)在相關(guān)的“UnpaidUsers”行,存有相同的郵件地址

這就意味著,我們想要的是分開的數(shù)據(jù)庫(kù)語(yǔ)句頭完成任務(wù)或者回滾。這個(gè)例子很好的說(shuō)明了這個(gè)交易。


首先,我們寫一些測(cè)試用例來(lái)驗(yàn)證事情是否按照我們想象的方式運(yùn)行: 
 

@mock.patch('payments.models.UnpaidUsers.save', side_effect = IntegrityError)
def test_registering_user_when_strip_is_down_all_or_nothing(self, save_mock):
 
  #create the request used to test the view
  self.request.session = {}
  self.request.method='POST'
  self.request.POST = {'email' : 'python@rocks.com',
             'name' : 'pyRock',
             'stripe_token' : '...',
             'last_4_digits' : '4242',
             'password' : 'bad_password',
             'ver_password' : 'bad_password',
            }    
 
  #mock out stripe and ask it to throw a connection error
  with mock.patch('stripe.Customer.create', side_effect =
          socket.error("can't connect to stripe")) as stripe_mock:
 
    #run the test
    resp = register(self.request)
 
    #assert there is no record in the database without stripe id.
    users = User.objects.filter(email="python@rocks.com")
    self.assertEquals(len(users), 0)
 
    #check the associated table also didn't get updated
    unpaid = UnpaidUsers.objects.filter(email="python@rocks.com")
    self.assertEquals(len(unpaid), 0)

當(dāng)我們嘗試去保存“UnpaidUsers”,測(cè)試上方的解釋器就會(huì)跑出異常'IntegrityError' 。

接下來(lái)是解釋這個(gè)問(wèn)題的答案,“當(dāng)“UnpaidUsers(email=cd['email']).save()”運(yùn)行的時(shí)候到底發(fā)生了什么?” 下面一段代碼創(chuàng)建了一段對(duì)話,我們需要在注冊(cè)函數(shù)中給出一些合適的信息。然后“with mock.patch” 會(huì)強(qiáng)制系統(tǒng)去認(rèn)為Stripe沒(méi)響應(yīng),最終就跳到我們的測(cè)試用例中。

resp = register(self.request)

上面這段話僅僅是調(diào)用我們的注冊(cè)視圖去傳遞請(qǐng)求。然后我們僅僅需要去核對(duì)表是否有更新:
 

#assert there is no record in the database without stripe_id.
users = User.objects.filter(email="python@rocks.com")
self.assertEquals(len(users), 0)
 
#check the associated table also didn't get updated
unpaid = UnpaidUsers.objects.filter(email="python@rocks.com")
self.assertEquals(len(unpaid), 0)

所以如果我們運(yùn)行了測(cè)試用例,那么它就該運(yùn)行失?。?br />  

======================================================================
FAIL: test_registering_user_when_strip_is_down_all_or_nothing (tests.payments.testViews.RegisterPageTests)
----------------------------------------------------------------------
Traceback (most recent call last):
 File "/Users/j1z0/.virtualenvs/django_1.6/lib/python2.7/site-packages/mock.py", line 1201, in patched
  return func(*args, **keywargs)
 File "/Users/j1z0/Code/RealPython/mvp_for_Adv_Python_Web_Book/tests/payments/testViews.py", line 266, in test_registering_user_when_strip_is_down_all_or_nothing
  self.assertEquals(len(users), 0)
AssertionError: 1 != 0
 
----------------------------------------------------------------------

贊。這就是我們最終想要的結(jié)果。

記住:我們這里已經(jīng)練習(xí)了“測(cè)試驅(qū)動(dòng)開發(fā)”的能力。錯(cuò)誤信息提示我們:用戶信息已經(jīng)被保存到數(shù)據(jù)庫(kù)中,但是這個(gè)并不是我們想要的,因?yàn)槲覀儾](méi)有付費(fèi)!

事務(wù)交易用于挽救這樣問(wèn)題 ...

事務(wù)

對(duì)于Django1.6,有很多種方式來(lái)創(chuàng)建事務(wù)。

這里簡(jiǎn)單介紹幾種。
推薦的方法

依據(jù)Django1.6的文檔,“Django提供了一種簡(jiǎn)單的API去控制數(shù)據(jù)庫(kù)的事務(wù)交易...原子操作用來(lái)定義數(shù)據(jù)庫(kù)事務(wù)的屬性。原子操作允許我們?cè)跀?shù)據(jù)庫(kù)保證的前提下,創(chuàng)建一堆代碼。如果這些代碼被成功的執(zhí)行,所對(duì)應(yīng)的改變也會(huì)提交到數(shù)據(jù)庫(kù)中。如果有異常發(fā)生,那么操作就會(huì)回滾?!?/p>

原子操作可以被用于解釋操作或者是內(nèi)容管理。所以如果我們用作為內(nèi)容管理的時(shí)候,我們的注冊(cè)函數(shù)的代碼就會(huì)如下:
 

from django.db import transaction
 
try:
  with transaction.atomic():
    user = User.create(cd['name'], cd['email'], cd['password'], cd['last_4_digits'])
 
    if customer:
      user.stripe_id = customer.id
      user.save()
    else:
      UnpaidUsers(email=cd['email']).save()
 
except IntegrityError:
  form.addError(cd['email'] + ' is already a member')

注意在“with transaction.atomic()”這一行。這塊代碼將會(huì)在事務(wù)內(nèi)部執(zhí)行。所以如果我們重新運(yùn)行了我們的測(cè)試,他們都將會(huì)通過(guò)。

記?。菏聞?wù)是一個(gè)工作單元,所以當(dāng)“UnpaidUsers”調(diào)用失敗的時(shí)候,內(nèi)容管理的所有操作都會(huì)被一起回滾。

使用裝飾器

除了上面的做法,我們能使用Python的裝飾器特性來(lái)使用事務(wù)。
 

@transaction.atomic():
def register(request):
  ...snip....
 
  try:
    user = User.create(cd['name'], cd['email'], cd['password'], cd['last_4_digits'])
 
    if customer:
      user.stripe_id = customer.id
      user.save()
    else:
        UnpaidUsers(email=cd['email']).save()
 
  except IntegrityError:
    form.addError(cd['email'] + ' is already a member')

如果我們重新跑一次測(cè)試,那還是會(huì)一樣失敗。

為啥呢?為啥事務(wù)沒(méi)有正確回滾呢?原因在與transaction.atomic會(huì)嘗試捕獲某種異常,而我們代碼里人肉捕抓了(例如 try-except 代碼塊里的IntegrityError 異常),所以 transaction.atomic 永遠(yuǎn)看不到這個(gè)異常,所以標(biāo)準(zhǔn)的AUTOCOMMIT 流程就此無(wú)效掉。

但是,刪掉try-catch語(yǔ)句會(huì)導(dǎo)致異常沒(méi)有捕獲,然后代碼流程十有八九會(huì)就此亂掉。所以啊,也就是說(shuō)不能去掉try-catch。
 


所以,技巧是將原子上下文管理器放入我們?cè)诘谝粋€(gè)解決方案中的 try-catch 代碼段里。

再看一下正確的代碼:
 

from django.db import transaction
 
try:
  with transaction.atomic():
    user = User.create(cd['name'], cd['email'], cd['password'], cd['last_4_digits'])
 
    if customer:
      user.stripe_id = customer.id
      user.save()
    else:
      UnpaidUsers(email=cd['email']).save()
 
except IntegrityError:
  form.addError(cd['email'] + ' is already a member')

當(dāng) UnpaidUsers 觸發(fā) IntegrityError 時(shí),上下文管理器 transaction.atomic() 會(huì)捕獲到它,并執(zhí)行回滾操作。此時(shí)我們的代碼在異常處理中執(zhí)行(即行 theform.addErrorline),將會(huì)完成回滾操作,并且,如果必要的話,也可以安全的進(jìn)行數(shù)據(jù)庫(kù)調(diào)用。也要注意:任何在上下文管理器 thetransaction.atomic() 前后的數(shù)據(jù)庫(kù)調(diào)用都不會(huì)受到它的執(zhí)行結(jié)果的影響。

針對(duì)每次HTTP請(qǐng)求的事務(wù)交易

Django1.5和1.6版本都允許用戶操作請(qǐng)求事務(wù)模式。在這種模式下,Django會(huì)自動(dòng)在事務(wù)中,處理你的視圖函數(shù)。如果視圖函數(shù)拋出異常,Django會(huì)自動(dòng)回滾事務(wù);否則Django會(huì)提交事務(wù)。

為了實(shí)現(xiàn)這個(gè)功能,你需要在你想要有此功能的數(shù)據(jù)庫(kù)的配置中,設(shè)置“ATOMIC_REQUEST”為真。所以在我們的“settings.py”需要有如下設(shè)置:
 

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.sqlite3',
    'NAME': os.path.join(SITE_ROOT, 'test.db'),
    'ATOMIC_REQUEST': True,
  }
}

如果我們把解釋器放到視圖函數(shù)中,以上設(shè)置就會(huì)生效。所以這并沒(méi)有符合我們的想法。

但是,這里依然值得注意的是解釋器:“ATOMIC_REQUESTS”和“@transaction.atomic”仍然會(huì)有可能在有異常拋出的時(shí)候,處理這些錯(cuò)誤。為了去捕捉這些錯(cuò)誤,你需要去完成一些常規(guī)的中間件,或者需要去覆蓋“urls.hadler500”,或者是創(chuàng)建新的“500.html”模板。

保存點(diǎn)

盡管事務(wù)是有原子性的,但還是能夠打散為多個(gè)“保存點(diǎn)”——你可看作是“部分事務(wù)”。

例如,你有個(gè)事務(wù)包含了4條SQL語(yǔ)句,你可以在第二個(gè)SQL之后創(chuàng)建一個(gè)保存點(diǎn)。一旦保存點(diǎn)創(chuàng)建成功,就算第三條或第四條SQL執(zhí)行失敗,你仍舊能夠做一個(gè)部分回滾,忽視后面兩條SQL,僅保留前面兩條。

基本上,這就像是提供了一個(gè)切割的能力:一個(gè)普通的事務(wù)能夠被切分為多個(gè)更“輕量”的事務(wù),然后能進(jìn)行部分回滾或部分提交。

    但一定要注意,小心整個(gè)事務(wù)被無(wú)端回滾掉(例如由于拋出了IntegrityError異常但卻沒(méi)有捕抓,那所有的保存點(diǎn)都會(huì)因此被回滾掉的)

來(lái)看個(gè)示例代碼,了解怎么玩轉(zhuǎn)保存點(diǎn)。

 

@transaction.atomic()
def save_points(self,save=True):
 
  user = User.create('jj','inception','jj','1234')
  sp1 = transaction.savepoint()
 
  user.name = 'zheli hui guadiao, T.T'
  user.stripe_id = 4
  user.save()
 
  if save:
    transaction.savepoint_commit(sp1)
  else:
    transaction.savepoint_rollback(sp1)

示例中,整個(gè)函數(shù)都是屬于一個(gè)事務(wù)的。新User對(duì)象創(chuàng)建后,我們創(chuàng)建并得到了一個(gè)保存點(diǎn)。然后后續(xù)3行語(yǔ)句——
 

  user.name = 'zheli hui guadiao, T.T'
  user.stripe_id = 4
  user.save()

——不屬于剛才的保存點(diǎn),因此他們有可能是屬于下面的savepoint_rollback或savepoint_commit的一部分。假設(shè)是savepoint_rollback, 那代碼行user = User.create('jj','inception','jj','1234')仍舊會(huì)成功提交到數(shù)據(jù)庫(kù)中 ,而下面三行則不會(huì)成功。
 

采用另外一種方法,下面的兩種測(cè)試用例描述了保存點(diǎn)是如何工作的:

 

def test_savepoint_rollbacks(self):
 
  self.save_points(False)
 
  #verify that everything was stored
  users = User.objects.filter(email="inception")
  self.assertEquals(len(users), 1)
 
  #note the values here are from the original create call
  self.assertEquals(users[0].stripe_id, '')
  self.assertEquals(users[0].name, 'jj')
 
 
def test_savepoint_commit(self):
  self.save_points(True)
 
  #verify that everything was stored
  users = User.objects.filter(email="inception")
  self.assertEquals(len(users), 1)
 
  #note the values here are from the update calls
  self.assertEquals(users[0].stripe_id, '4')
  self.assertEquals(users[0].name, 'starting down the rabbit hole')

同樣,在我們提交或者回滾保存點(diǎn)之后,我們?nèi)匀豢梢岳^續(xù)在同一個(gè)事務(wù)中工作。同時(shí),這個(gè)運(yùn)行結(jié)果不受之前保存點(diǎn)輸出結(jié)果的影響。

例如,如果我們按照如下例子更新“save_points”函數(shù),

 

@transaction.atomic()
def save_points(self,save=True):
 
  user = User.create('jj','inception','jj','1234')
  sp1 = transaction.savepoint()
 
  user.name = 'starting down the rabbit hole'
  user.save()
 
  user.stripe_id = 4
  user.save()
 
  if save:
    transaction.savepoint_commit(sp1)
  else:
    transaction.savepoint_rollback(sp1)
 
  user.create('limbo','illbehere@forever','mind blown',
      '1111')

即使無(wú)論是“savepoint_commit”或者“savepoint_rollback”被“l(fā)imbo”這個(gè)用戶調(diào)用了,這個(gè)事務(wù)仍然會(huì)被成功創(chuàng)建。如果沒(méi)有創(chuàng)建成功,整個(gè)事務(wù)將會(huì)被回滾。

嵌套事務(wù)

采用“savepoint()”,“savepoint_commit”和“savepoint_rollback”去手動(dòng)指定保存點(diǎn),將會(huì)自動(dòng)一個(gè)嵌套事務(wù),同時(shí)這個(gè)嵌套事務(wù)會(huì)自動(dòng)為我們創(chuàng)建一個(gè)保存點(diǎn)。并且,如果我們遇到錯(cuò)誤,這個(gè)事務(wù)將會(huì)回滾。

下面用一個(gè)擴(kuò)展的例子來(lái)說(shuō)明:
 

@transaction.atomic()
def save_points(self,save=True):
 
  user = User.create('jj','inception','jj','1234')
  sp1 = transaction.savepoint()
 
  user.name = 'starting down the rabbit hole'
  user.save()
 
  user.stripe_id = 4
  user.save()
 
  if save:
    transaction.savepoint_commit(sp1)
  else:
    transaction.savepoint_rollback(sp1)
 
  try:
    with transaction.atomic():
      user.create('limbo','illbehere@forever','mind blown',
          '1111')
      if not save: raise DatabaseError
  except DatabaseError:
    pass

這里我們可以看到:在我們處理保存點(diǎn)之后,我們采用“thetransaction.atomic”的上下文管理區(qū)擦出我們創(chuàng)建的"limbo"這個(gè)用戶。當(dāng)上下文管理被調(diào)用的時(shí)候,它會(huì)創(chuàng)建一個(gè)保存點(diǎn)(因?yàn)槲覀円呀?jīng)在事務(wù)里面了),同時(shí)這個(gè)保存點(diǎn)將會(huì)依據(jù)已經(jīng)存在的上下文管理器去被執(zhí)行或者回滾。

這樣下面兩個(gè)測(cè)試用例就描述了這個(gè)行文:

 
 

def test_savepoint_rollbacks(self):
 
     self.save_points(False)
 
    #verify that everything was stored
    users = User.objects.filter(email="inception")
    self.assertEquals(len(users), 1)
 
    #savepoint was rolled back so we should have original values
    self.assertEquals(users[0].stripe_id, '')
    self.assertEquals(users[0].name, 'jj')
 
    #this save point was rolled back because of DatabaseError
    limbo = User.objects.filter(email="illbehere@forever")
    self.assertEquals(len(limbo),0)
 
  def test_savepoint_commit(self):
    self.save_points(True)
 
    #verify that everything was stored
    users = User.objects.filter(email="inception")
    self.assertEquals(len(users), 1)
 
    #savepoint was committed
    self.assertEquals(users[0].stripe_id, '4')
    self.assertEquals(users[0].name, 'starting down the rabbit hole')
 
    #save point was committed by exiting the context_manager without an exception
    limbo = User.objects.filter(email="illbehere@forever")
    self.assertEquals(len(limbo),1)


因此,在現(xiàn)實(shí)之中你可以使用原子或者在事務(wù)之中創(chuàng)建保存點(diǎn)的保存點(diǎn)。使用原子,你不必要很仔細(xì)地?fù)?dān)心提交和會(huì)滾,當(dāng)這種情況發(fā)生時(shí),你可以完全控制其中的保存點(diǎn)。
結(jié)論

如果你有任何以往使用Django更早版本事務(wù)處理的經(jīng)驗(yàn),你可以看到很多更簡(jiǎn)單地事務(wù)處理模型。如下,在默認(rèn)情況下,也有自動(dòng)提交功能,它是一個(gè)很好的例子,即Django與python兩者都引以為豪所提供的“理智的”默認(rèn)值。對(duì)于如此多的系統(tǒng),你將不需要直接地來(lái)處理事務(wù)。只是讓“自動(dòng)提交功能”來(lái)完成其工作,但如果你這樣做,我將希望這個(gè)帖子能提供你所需要像專家一樣在Django之中管理的事務(wù)處理。
 

相關(guān)文章

  • Python面向?qū)ο蟮膬?nèi)置方法梳理講解

    Python面向?qū)ο蟮膬?nèi)置方法梳理講解

    面向?qū)ο缶幊淌且环N編程方式,此編程方式的落地需要使用“類”和 “對(duì)象”來(lái)實(shí)現(xiàn),所以,面向?qū)ο缶幊唐鋵?shí)就是對(duì) “類”和“對(duì)象” 的使用,今天給大家介紹下python 面向?qū)ο箝_發(fā)及基本特征,感興趣的朋友一起看看吧
    2022-10-10
  • 使用Python機(jī)器學(xué)習(xí)降低靜態(tài)日志噪聲

    使用Python機(jī)器學(xué)習(xí)降低靜態(tài)日志噪聲

    今天小編就為大家分享一篇關(guān)于使用Python和機(jī)器學(xué)習(xí)的靜態(tài)日志噪聲的文章,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-09-09
  • Python實(shí)現(xiàn)調(diào)用攝像頭拍攝照片

    Python實(shí)現(xiàn)調(diào)用攝像頭拍攝照片

    這篇文章主要為大家詳細(xì)介紹了如何利用Python實(shí)現(xiàn)調(diào)用攝像頭拍攝照片以及郵箱收集功能,文中的示例代碼講解詳細(xì),感興趣的可以動(dòng)手嘗試一下
    2022-06-06
  • Python中使用MELIAE分析程序內(nèi)存占用實(shí)例

    Python中使用MELIAE分析程序內(nèi)存占用實(shí)例

    這篇文章主要介紹了Python中使用MELIAE分析程序內(nèi)存占用實(shí)例,本文直接給出使用代碼示例,需要的朋友可以參考下
    2015-02-02
  • OpenCV灰度化之后圖片為綠色的解決

    OpenCV灰度化之后圖片為綠色的解決

    這篇文章主要介紹了OpenCV灰度化之后圖片為綠色的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • python實(shí)現(xiàn)plt x軸坐標(biāo)按1刻度顯示

    python實(shí)現(xiàn)plt x軸坐標(biāo)按1刻度顯示

    這篇文章主要介紹了python實(shí)現(xiàn)plt x軸坐標(biāo)按1刻度顯示,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • 基于Python編寫一個(gè)爆炸信息窗口腳本

    基于Python編寫一個(gè)爆炸信息窗口腳本

    這篇文章主要為大家詳細(xì)介紹了如何利用Python語(yǔ)言編寫一個(gè)爆炸信息窗口腳本,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下
    2022-11-11
  • 如何利用Python將html轉(zhuǎn)為pdf、word文件

    如何利用Python將html轉(zhuǎn)為pdf、word文件

    網(wǎng)絡(luò)上存在很多將HTML轉(zhuǎn)換為PDF的軟件和工具,但是大家都知道收費(fèi),所以下面這篇文章主要給大家介紹了關(guān)于如何利用Python將html轉(zhuǎn)為pdf、word文件的相關(guān)資料,文中通過(guò)示例代碼介紹介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • 詳解Python調(diào)用系統(tǒng)命令的六種方法

    詳解Python調(diào)用系統(tǒng)命令的六種方法

    這篇文章主要介紹了詳解Python調(diào)用系統(tǒng)命令的六種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • python批量生成條形碼的示例

    python批量生成條形碼的示例

    這篇文章主要介紹了python批量生成條形碼的示例,幫助大家更好的利用python處理圖形,感興趣的朋友可以了解下
    2020-10-10

最新評(píng)論

平山县| 延寿县| 清河县| 兴安盟| 永登县| 新乡县| 五家渠市| 长顺县| 张掖市| 黑山县| 磴口县| 富源县| 安吉县| 西城区| 丹巴县| 会昌县| 诸城市| 东乌珠穆沁旗| 定陶县| 民乐县| 昔阳县| 安溪县| 武胜县| 乐昌市| 光泽县| 通辽市| 伊金霍洛旗| 淄博市| 西乡县| 盐源县| 华容县| 玉环县| 武定县| 桂林市| 比如县| 江城| 朝阳县| 扶绥县| 丹棱县| 叶城县| 河北省|