django后台使用MySQL情况下的事务控制详解

 

写在前面:

  默认情况下django会把autocommit设置为“1”也就是说所针对数据库的每一次操作都会被做成“单独”的一个事务;这样的处理好处就在于它方便,

  在编程的时候可以少写一些代码,比如我们不用先“start transaction ” 操作完之后再“commit” 或 “rollback”。

 

 

django对事务控制的实现方式:

  django中通过transaction.atomic()上下文来完成事务控制

    try:
        with transaction.atomic():
            # 对数据库的操作
    except Exception as e:
        # 异常处理
    
    #其它处理逻辑

 

以学院式的银行转账业务为例:

  1):一张表示银行存款的表(为了突出事务控制在些不对表进行过多的设计)

from django.db import models

# Create your models here.

class SavingCard(models.Model):
    name=models.CharField(max_length=64,default='',null=False)
    saving = models.DecimalField(max_digits=16,decimal_places=4,default=0,null=False)

  以上模型它所对应的SQL语句如下

CREATE TABLE `bank_savingcard` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(64) NOT NULL,
  `saving` decimal(16,4) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

 

  手工在数据库中插入两行测试数据

insert into bank_savingcard(name,saving) values
      ('jianglexing',100),('welson',80);

 

  2):用django实现一个转账功能的view

from django.shortcuts import render
from .models import SavingCard
from django.db import transaction
from django.http import HttpResponse
# Create your views here.

def transfer(request,fromname,toname,count):
    """
    完整的转账功能
    """

    try:
        with transaction.atomic():
            if count < 0:
                raise ValueError("转账资金不得小于0元")
            
            fromAccount = SavingCard.objects.get(name=fromname)
            toAccount   = SavingCard.objects.get(name=toname)
            if count > fromAccount.saving:
                raise ValueError("转账资金不得大于卡内余额")

            fromAccount.saving=fromAccount.saving-count
            toAccount.saving = toAccount.saving + count

            fromAccount.save()
            toAccount.save()
    except Exception as e:
        return HttpResponse("<p>{} {}</p>".format("出现异常转账失败",e))
    return HttpResponse("转账成功")

  注册转账接口

from django.contrib import admin
from django.urls import path
from bank.views import transfer

urlpatterns = [
    path('admin/', admin.site.urls),
    path('bank/<str:fromname>/transaction/<str:toname>/<int:count>/',transfer)
]

 

  3):调用转账接口

http://127.0.0.1:8080/bank/jianglexing/transaction/welson/5/

  jianglexing转5元给welson

 

  4):转账前后数据库的内容变化

select * from bank_savingcard;
+----+-------------+----------+
| id | name        | saving   |
+----+-------------+----------+
|  1 | jianglexing | 100.0000 |
|  2 | welson      |  80.0000 |
+----+-------------+----------+
2 rows in set (0.00 sec)

 select * from bank_savingcard;
+----+-------------+---------+
| id | name        | saving  |
+----+-------------+---------+
|  1 | jianglexing | 95.0000 |
|  2 | welson      | 85.0000 |
+----+-------------+---------+
2 rows in set (0.00 sec)

 

  5):强行转账1000元看一下

http://127.0.0.1:8080/bank/jianglexing/transaction/welson/1000/

 

  前后的数据库内容对比

select * from bank_savingcard;
+----+-------------+---------+
| id | name        | saving  |
+----+-------------+---------+
|  1 | jianglexing | 95.0000 |
|  2 | welson      | 85.0000 |
+----+-------------+---------+
2 rows in set (0.00 sec)

select * from bank_savingcard;
+----+-------------+---------+
| id | name        | saving  |
+----+-------------+---------+
|  1 | jianglexing | 95.0000 |
|  2 | welson      | 85.0000 |
+----+-------------+---------+
2 rows in set (0.00 sec)

 

  6):强行转账1000到一个不存在的账号

 

 

 

----------------------------------------------------------------------------------------------

 

posted on 2018-05-04 08:33  蒋乐兴的技术随笔  阅读(375)  评论(0编辑  收藏  举报

导航