您當前的位置:首頁 > 農業

Django 知識庫:transaction事務

作者:由 杜賽 發表于 農業時間:2020-06-11

有些時候我們需要

對資料庫進行一連串的操作

,如果其中某一個操作失敗,那麼其他的操作也要跟著回滾到操作以前的狀態。

舉個例子。某天你到銀行存了 100 塊錢,所以你的賬戶的資料庫表就應該減去 100 塊,而銀行的賬戶上增加 100 塊。但如果資料庫在執行銀行賬戶增加 100 塊時操作失敗了,豈不是平白無故損失掉 100 塊錢,那你不得把銀行屋頂給拆了。

這種情況下就需要用到

事務

這個概念了,即把一組操作捆綁到一起,大家生死與共,要麼都成功,要麼都失敗,結成人民統一戰線。

Django 裡如何實現事務?看下面的例子:

# models。py

from

django。db

import

models

class

Student

models

Model

):

“”“學生”“”

name

=

models

CharField

max_length

=

20

class

Info

models

Model

):

“”“學生的基本情況”“”

age

=

models

IntegerField

()

class

Address

models

Model

):

“”“學生的家庭住址”“”

home

=

models

CharField

max_length

=

100

有三個模型,

Student

為學生、

Info

為學生的基本情況、

Address

為學生的住址。

假設這三個模型必須同時建立,否則資料就是不完整的。

我們可以這樣寫檢視:

def

create_student

request

):

student

=

Student

objects

create

name

=

‘張三’

info

=

Info

objects

create

age

=

19

address

=

Address

objects

create

home

=

‘北京’

return

HttpResponse

‘Create success。。。’

很正常對吧。接下來讓程式故意引發錯誤:

def

create_student

request

):

student

=

Student

objects

create

name

=

‘張三’

info

=

Info

objects

create

age

=

19

# 引發錯誤

oh_my_god

=

int

‘abc’

address

=

Address

objects

create

home

=

‘北京’

return

HttpResponse

‘Create success。。。’

這就有問題了,前面的

Student

Info

都正常儲存進資料庫了,但是

Address

卻由於前一句報錯而沒有執行建立,因此學生資訊就變成了不完整的垃圾資料了。

解決辦法就是把檢視函式中的資料操作轉化為

事務

from

django。db

import

transaction

# 注意這個裝飾器

@transaction。atomic

def

create_student

request

):

student

=

Student

objects

create

name

=

‘張三’

info

=

Info

objects

create

age

=

19

oh_my_god

=

int

‘abc’

address

=

Address

objects

create

home

=

‘北京’

return

HttpResponse

‘Create success。。。’

這就非常不同了。無論視圖裡哪一個資料庫操作失敗或是沒有執行,那麼其他的操作也都會回滾到操作前的狀態。也就是說上面這段程式碼中的三個模型,都沒有儲存成功。

有的時候視圖裡有很多的資料操作,如果我只想回滾其中一部分為事務也是有辦法的:

from

django。db

import

transaction

@transaction。atomic

def

create_student

request

):

student

=

Student

objects

create

name

=

‘張三’

# 回滾儲存點

save_tag

=

transaction

savepoint

()

try

info

=

Info

objects

create

age

=

19

# 引發錯誤

oh_my_god

=

int

‘abc’

address

=

Address

objects

create

home

=

‘北京’

except

# 回滾到 save_tag 的位置

transaction

savepoint_rollback

save_tag

return

HttpResponse

‘Create success。。。’

上面的程式碼執行之後,

Student

表會成功儲存,而另外兩張表則都會失敗。使用

try

的好處在於前端能正常執行。

除此之外,還有另一種方法可以將檢視中的事務進行分組,實現更細膩的控制:

# 裝飾器不要了

# @transaction。atomic

def

create_student

request

):

student

=

Student

objects

create

name

=

‘張三’

# 事務

with

transaction

atomic

info

=

Info

objects

create

age

=

19

# 引發錯誤

oh_my_god

=

int

‘abc’

address

=

Address

objects

create

home

=

‘北京’

return

HttpResponse

‘Create success。。。’

效果是差不多的,僅有

Student

成功儲存。

還有最後一個大殺器。如果你想讓所有的資料庫操作都是事務,那就在

settings。py

裡配置:

# settings。py

# 以 sqlite 為例

DATABASES

=

{

‘default’

{

‘ENGINE’

。。。

‘NAME’

。。。

# 加上這條

‘ATOMIC_REQUESTS’

True

}

}

然後可以用

non_atomic_requests

標記不需要成為事務的檢視:

@transaction。non_atomic_requests

def

create_student

request

):

。。。

另外,

類檢視

也是可以成為事務的:

class

CreateStudent

View

):

@transaction。atomic

def

get

self

request

):

。。。

最後總結一下,並非任意對資料庫的操作序列都是事務。資料庫事務擁有 ACID特性:

原子性(Atomicity)

:事務作為一個整體被執行,包含在其中的對資料庫的操作要麼全部被執行,要麼都不執行。

一致性(Consistency)

:事務應確保資料庫的狀態從一個一致狀態轉變為另一個一致狀態。一致狀態的含義是資料庫中的資料應滿足完整性約束。

隔離性(Isolation)

:多個事務併發執行時,一個事務的執行不應影響其他事務的執行。

永續性(Durability)

:已被提交的事務對資料庫的修改應該永久儲存在資料庫中。

關聯官方文件:Database transactions

標簽: objects  create  student  事務  資料庫