Django之深刻了解ORM

Django ORM操做

經常使用字段

models中全部的字段類型其實本質就那幾種,整形varchar什麼的,都沒有實際的約束做用,雖然在models中沒有任何限制做用,可是仍是要分門別類,對於校驗性組件校驗很是有用
就好比說郵箱類型,你在輸入郵箱的時候若是不按照郵箱格式輸入,瞎雞兒輸入會提示你不合法,雖然輸入的是字符串,可是不是規定的郵箱字符串git

字段 描述
AutoField int自增列,必須填入參數 primary_key=True。當model中若是沒有自增列,則自動會建立一個列名爲id的列。
IntegerField 一個整數類型,範圍在 -2147483648 to 2147483647。(通常不用它來存手機號(位數也不夠),直接用字符串存,)
BigIntegerField
CharField 字符類型對應MySQL的varchar類型,必須提供max_length參數, max_length表示字符長度。
DateField 日期時間字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],至關於Python中的datetime.datetime()實例。
DecimalField 10進制小數, max_digits,小數總長度 ,decimal_places,小數位長度
EmailField email字段,內部仍是varchar(254)
BooleanField 布爾值,傳True或False,自動轉成1/0
TextField 存儲大段文本
FileField 專門用來存放文件路徑,傳值的時候,直接傳文件對象,將路徑保存到數據庫
關係字段 描述
ForeignKey 關係字段,外鍵類型在ORM中用來表示外鍵關聯關係,通常把ForeignKey字段設置在 '一對多'中'多'的一方。
OneToOneField 一對一字段。
ManyToManyField 多對多表關係而且這一張多對多的關係表是有Django自動幫你建

經常使用字段參數

參數 描述
null 用於表示某個字段能夠爲空。
unique 若是設置爲unique=True 則該字段在此表中必須是惟一的 。
db_index 若是db_index=True 則表明着爲此字段設置索引。
default 爲該字段設置默認值。
DateField和DateTimeField 描述
auto_now_add 配置auto_now_add=True,建立數據記錄的時候會把當前時間添加到數據庫。
auto_now 配置上auto_now=True,每次更新數據記錄的時候會更新該字段。
關係字段參數 描述
to 設置要關聯的表
to_field 設置要關聯的表的字段
on_delete 當刪除關聯表中的數據時,當前表與其關聯的行的行爲。
db_constraint 是否在數據庫中建立外鍵約束,默認爲True。

自定義字段

Django中的CharField對應的MySQL數據庫中的varchar類型,沒有設置對應char類型的字段,sql

可是Django容許咱們自定義新的字段,下面我來自定義對應於數據庫的char類型數據庫

自定義字段在實際項目應用中可能會常常用到django

from django.db import models

# Create your models here.
#Django中沒有對應的char類型字段,可是咱們能夠本身建立
class FixCharField(models.Field):
    '''
    自定義的char類型的字段類
    '''
    def __init__(self,max_length,*args,**kwargs):
        self.max_length=max_length
        super().__init__(max_length=max_length,*args,**kwargs)

    def db_type(self, connection):
        '''
        限定生成的數據庫表字段類型char,長度爲max_length指定的值
        :param connection:
        :return:
        '''
        return 'char(%s)'%self.max_length
    
#應用上面自定義的char類型
class Class(models.Model):
    id=models.AutoField(primary_key=True)
    title=models.CharField(max_length=32)
    class_name=FixCharField(max_length=16)

字段合集和對應關係併發

咱們來建立一張表:app

models.py:
class Books(models.Model):
    title = models.CharField(max_length=254)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish_date = models.DateField()

將表同步到MySQL中:
python3 manage.py makemigrations
python3 manage.py migrate

而後咱們在django測試文件中,若是單純的測試某個py文件,須要手動配置測試腳本函數

app01/tests.py:
# Create your tests here.
import os
if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
    import django
    django.setup()
    from app01 import models
    # 下面開始寫測試的代碼。
    
    
    # 建立數據------------------------------------------------------------------------
    # 1. create 方法
    models.Books.objects.create(title='三國演義',price=123,publish_date='2019-11-11')

    from datetime import date
    ctime = date.today()
    models.Books.objects.create(title='紅樓夢',price=888,publish_date=ctime)

    # 2. 利用對象的綁定方法建立數據
    book_obj = models.Books(title='西遊記',price=666,publish_date='2000-11-11')
    book_obj.save()
    # 插入的數據
    # id    title     price   publish_date
    # 4     三國演義    123     2019-11-11
    # 5     紅樓夢     888     2019-11-27
    # 6     西遊記     666     2000-11-11

    # 修改數據------------------------------------------------------------------------
    '''
        利用filter 自動查詢當前表的主鍵字段,pk表明primary_key
        filter查詢出來的是一個queryset對象:
            只要是queryset的對象就能夠無限制的調用queryset的方法
            只要是queryset的對象就能夠點query查看當前結果內部對應的sql語句
    '''
    # 1. 利用queryset方法修改數據
    models.Books.objects.filter(pk=4).update(price=444)
    # 2. 利用對象方法修改數據
    book_obj = models.Books.objects.get(pk=1)
    book_obj.price = 222
    book_obj.save()     # 不推薦使用,推薦使用queryset方法
    '''
        利用對象修改,內部實際上是將全部的字段從新寫進去
        get 和 filter的區別:
            filter 獲取到的是一個queryset對象,相似於一個列表,沒有數據的時候不會報錯
            get獲取到的數據就是數據自己,可是沒有數據的時候會報錯
    '''

    # 刪除數據------------------------------------------------------------------------
    # 1. 利用queryset方法 :delete()
    models.Books.objects.filter(pk=4).delete()
    # 2. 對象的方法
    book_obj = models.Books.objects.get(pk=4)
    book_obj.delete()

    
    
    
    
# 若是你想直接查看全部的orm語句內部對應的sql語句,能夠在配置文件中配置: 
settings.py:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

單表操做

方法(加括號使用) 描述
all 查詢全部,返回QuerySet對象
filter 篩選,至關於原生SQL的where條件,返回QuerySet對象
get 篩選,獲取數據對象自己,若是不存在報錯,而且查詢條件必須是惟一的。
first 取QuerySet對象中第一個數據對象
last 取QuerySet對象中最後一個數據對象
count 統計數據的條數
values 獲取數據對象中指定的字段的值,返回列表套字典的QuerySet對象
values_list 獲取數據對象中指定的字段的值,返回列表套元組的QuerySet對象
order_by 指定字段進行排序,默認升序,在字段前加-是降序
reverse 顛倒順序,前提是顛倒的對象必須有順序,也就是order_by事後的
exclude 查詢排除什麼以外,返回QuerySet對象
exists 判斷查詢結果是否有值,返回布爾值
distinct 對指定字段查詢出來的結果進行去重操做
# 查詢數據 13 條------------------------------------------------------------------------
# 1. all()  查詢全部,返回queryset對象
print(models.Books.objects.all())

# 2. filter()   篩選 至關於原生sql語句裏面的where關鍵字,返回queryset對象
print(models.Books.objects.filter(pk=4))

# 3. get()  篩選  獲取的數據是對象自己,數據不存在直接報錯,而且查詢條件必須惟一,返回數據對象自己
print(models.Books.objects.get(pk=4))

# 4. first()    獲取queryset對象中第一個數據對象    返回數據對象
print(models.Books.objects.filter(pk=4).first())

# 5. last()     獲取queryset對象中最後一個數據對象    返回數據對象
print(models.Books.objects.filter(pk=4).last())

# 6. count()    統計數據的條數     返回數字
print(models.Books.objects.count())

# 7. values()   獲取數據對象中指定的字段的值,能夠指定多個,返回queryset對象,列表套字典
print(models.Books.objects.values('title','price'))

# 8. values_list()  獲取數據對象中指定的字段的值,能夠指定多個,返回queryset對象,列表套元組
print(models.Books.objects.values_list('title','price'))

# 9. order_by()   按照指定的字段排序,默認是升序,在字段前面加 - 是降序
print(models.Books.objects.order_by('pk').values('pk'))
print(models.Books.objects.order_by('-pk').values('pk'))

# 10. reverse()     顛倒順序,前提是顛倒的對象必須有順序,排序以後的
print(models.Books.objects.order_by('pk').reverse().values('pk'))

# 11. exclude()     查詢條件排除什麼
print(models.Books.objects.exclude(pk=4).values('pk'))

# 12. exists()      判斷查詢結果是否有值,返回的是布爾值
print(models.Books.objects.exists())

# 13. distinct()    對查詢結果去重,前提是數據徹底相同的狀況下
print(models.Books.objects.values('title','price').distinct())

雙下劃線查詢

方法 描述
**__gt** 字段大於什麼什麼值
**__lt** 字段小於什麼什麼值
**__gte** 字段大於等於什麼值
**__lte** 字段小於等於什麼值
**__in** 字段是什麼或什麼的值,or的關係
**__range** 字段是什麼和什麼之間的值,btwen..and...
**__year** 字段的年份是什麼什麼的值
**__month** 字段的月份是什麼什麼的值
# 下劃線查詢------------------------------------------------------------------------
# 1. 查詢價格大於500的書
print(models.Books.objects.filter(price__gt=500).values('title'))

# 2. 查詢價格小於500的書籍
print(models.Books.objects.filter(price__lt=500).values('title'))

# 3. 查詢價格大於等於500的書籍
print(models.Books.objects.filter(price__gte=500).values('title'))

# 4. 查詢價格小於等於500的書籍
print(models.Books.objects.filter(price__lte=500).values('title'))

# 5. 查詢價格是222 或 444 或 500 的書籍
print(models.Books.objects.filter(price__in=[222,444,500]).values('title'))

# 6. 查詢價格在200到800之間的書籍      顧頭也顧尾
print(models.Books.objects.filter(price__range=(200,800)).values('title'))

# 7. 查詢出版日期是2019年的書籍
print(models.Books.objects.filter(publish_date__year='2019').values('title'))

# 8. 查詢出版日期是11月份的書籍
print(models.Books.objects.filter(publish_date__month='11').values('title'))

模糊查詢

MySQL中的模糊查詢,關鍵字like,模糊匹配的符號:%_測試

方法 描述
**__startswith** 字段的值以什麼什麼開頭的值
**__endswith** 字段的值以什麼什麼結尾的值
**__contanins** 字段的值包含什麼什麼的值,區分大小寫
**__icontanins** 字段的值包含什麼什麼的值,不區分大小寫
# 模糊查詢------------------------------------------------------------------------
# 1. 查詢書籍是以三開頭的書
print(models.Books.objects.filter(title__startswith='三').values('title'))

# 2. 查詢書籍是以三結尾的書
print(models.Books.objects.filter(title__endswith='三').values('title'))

# 3. 查詢書籍名稱中包含遊字的書籍
print(models.Books.objects.filter(title__contains='遊').values('title'))

# 4. 查詢書籍名稱中包含字母p的書籍,區分大小寫
print(models.Books.objects.filter(title__contains='p').values('title'))

# 5. 查詢書籍名稱中包含字母p的書籍,區分大小寫
print(models.Books.objects.filter(title__icontains='p').values('title'))

多表操做

一對多字段數據的操做

爲了方便操做,咱們建立圖書管理系統相關表來演示多表操做atom

models.py:

class Book(models.Model):
    title = models.CharField(max_length=254)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish_date = models.DateField(auto_now_add=True)
    '''
    auto_now :每次修改數據的時候,會自動更新時間
    auto_now_add :當數據建立出來的時候,自動將建立時間記錄下來
    '''
    publish = models.ForeignKey(to='Publish')
    authors = models.ManyToManyField(to='Author')

class Publish(models.Model):
    name = models.CharField(max_length=254)
    addr = models.CharField(max_length=254)

class Author(models.Model):
    name = models.CharField(max_length=254)
    email = models.EmailField(max_length=254)
    author_detail = models.OneToOneField(to='AuthorDetail')

class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    add = models.CharField(max_length=254)
# 一對多字段數據的增刪改查------------------------------------------------------------------------
# 一對一字段的數據的修改和一對多同樣的。
# 增
# 第一種方式:
publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.create(title='紅樓夢',price=444,publish=publish_obj)
# 第二種方式:
models.Book.objects.create(title='三國演義',price=222,publish_id=1)

# 改
# 第一種方式:
models.Book.objects.filter(pk=2).update(publish_id=2)
# 第二種方式:
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=2).update(publish=publish_obj)

# 刪 默認就是級聯刪除,級聯更新
models.Publish.objects.filter(pk=1).delete()

多對多字段數據的操做

方法 描述
add 可以在第三張表中添加數據既支持傳數字,也支持傳對象,能夠傳多個值
set 修改第三張表中的數據,須要傳一個可迭代對象進去例如元組,列表,容器類元素能夠是數字或者對象
remove 刪除第三張表中的數據,既支持傳數字,也支持傳對象,能夠傳多個值
clear 清空 刪除書籍相關的記錄,下線,括號內不須要傳遞參數
# 多對多字段數據的增刪改查------------------------------------------------------------------------
# 增
book_obj = models.Book.objects.filter(pk=2).first()
# print(book_obj.authors)
# app01.Author.None 表示着已經跨到第三張表了
# 給當前這一本書綁定做者,能夠寫多個
book_obj.authors.add(1)
book_obj.authors.add(1,2)

# 也能夠增長對象
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj1,author_obj2)

'''
    add 方法:
        可以在第三張表中添加數據
        既支持傳數字,也支持傳對象,能夠傳多個值
    '''

# 改
# 修改id爲2的書籍的做者
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.set((1,))
book_obj.authors.set((1,2))

# 也能夠修改成對象
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
book_obj.authors.set((author_obj1,author_obj2))

'''
    set 方法:
        修改第三張表中的數據,
        須要傳一個可迭代對象進去例如元組,列表,
        容器類元素能夠是數字或者對象
    '''

# 刪
# 刪除id爲2的書籍的做者
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.author.remove(1,2)

# 也能夠傳對象
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
book_obj.author.remove(author_obj1, author_obj2)

'''
    remove 方法:
        刪除第三張表中的數據,既支持傳數字,也支持傳對象,能夠傳多個值
    '''

# 清空:
# 刪除id爲2 的書籍(包括做者信息也刪除)
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.clear()

'''
    clear 方法:
        清空 刪除書籍相關的記錄,下線,括號內不須要傳遞參數
    '''

跨表查詢

在使用跨表查詢的時候,要注意一點,

要明白關係字段在哪一方?

從有關係字段的那一方查的話就是正向查詢,查詢按關係字段查詢查。

從沒有關係字段的那一方查的話就是反向查詢,查詢按小寫的表名查。

基於對象的跨表查詢

方法 描述
all() 當正向查詢點擊外鍵字段數據有多個的狀況下也就是多對多查詢,須要加.all()
**_set** 反向查詢的時候 表名小寫而且加_set

子查詢

# 跨表查詢------------------------------------------------------------------------
# 基於對象的跨表查詢
# 1. 查詢書籍主鍵爲2的出版社名稱
# 正向查詢,先查書籍對象,一對多查詢
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.publish.name)

# 2. 查詢書籍主鍵爲2的做者姓名
# 正向查詢,先查書籍對象,多對多查詢
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.authors)     # app01.Author.None
print(book_obj.authors.all().values('name'))

# 3. 查詢做者是qinyj的手機號碼
# 正向查詢,先查做者對象,一對一查詢
author_obj = models.Author.objects.filter(name='qinyj').first()
print(author_obj.author_detail.phone)

'''
    何時須要加 all:
        當正向查詢點擊外鍵字段數據有多個的狀況下
        也就是多對多查詢,須要加.all()
    '''

# 4. 查詢出版社是東方出版社出版過的書籍
# 反向查詢,先查出版社對象,一對多查詢
publish_obj = models.Publish.objects.filter(name='東方出版社').first()
print(publish_obj.book_set.all().values('title'))

# 5. 查詢做者是qinyj寫過的書籍
# 反向查詢,先查做者對象,多對多查詢
author_obj = models.Author.objects.filter(name='qinyj').first()
print(author_obj.book_set.all().values('title'))

# 6. 查詢手機號是111111的做者姓名
# 反向查詢,先查做者詳情表的對象,一對一查詢
author_detail_obj = models.AuthorDetail.objects.filter(phone='111111').first()
print(author_detail_obj.author.name)

'''
    何時反向查詢的時候表名小寫而且加_set
        一對多
        多對多
        一對一不須要加
    '''

基於雙下劃線的跨表查詢

聯表查詢

雙下劃線,鏈式操做:__

# 基於雙下劃線的跨表查詢 聯表操做------------------------------------------------------------------------
# 1. 查詢書籍id爲2的出版社名稱
# 正向查詢:
# values中寫外鍵名就至關於跨到外鍵字段所在的表中了
print(models.Book.objects.filter(pk=2).values('publish__name'))
# 反向查詢:
print(models.Publish.objects.filter(book__pk=2).values('name'))

# 2. 查詢書籍id爲2的做者的姓名
# 正向查詢:
print(models.Book.objects.filter(pk=2).values('authors__name'))
# 反向查詢:
print(models.Author.objects.filter(book__pk=2).values('name'))

# 3. 查詢做者是qinyj的地址
# 正向查詢:
print(models.Author.objects.filter(name='qinyj').values('author_detail__add'))
# 反向查詢:
print(models.AuthorDetail.objects.filter(author__name='qinyj').values('add'))

# 4. 查詢出版社是東方出版社出版過的書的名字
# 正向查詢:
print(models.Book.objects.filter(publish__name='東方出版社').values('title'))
# 反向查詢:
print(models.Publish.objects.filter(name='東方出版社').values('book__title'))

# 5. 查詢書籍id是2的做者的手機號
# 正向查詢:
print(models.Book.objects.filter(pk=2).values('authors__author_detail__phone'))
# 反向查詢:
print(models.Author.objects.filter(book__pk=2).values('author_detail__phone'))

聚合函數

aggregate

聚合函數 描述
Max 最大值
Min 最小值
Sum 求和
Count 計數
Avg 平均數
'''
    聚合函數
    '''
from django.db.models import Max,Min,Count,Avg,Sum

# 篩選出價格最高的書籍
print(models.Book.objects.aggregate(ct=Count('price'))) # {'ct': 2}

# 篩選出價格最低的書籍
print(models.Book.objects.aggregate(mn=Min('price')))   # {'mn': Decimal('222.00')}

# 求書籍價格總和
print(models.Book.objects.aggregate(sm=Sum('price')))   # {'sm': Decimal('666.00')}

# 求書籍價格平均值
print(models.Book.objects.aggregate(ag=Avg('price')))   # {'ag': 333.0}

# 聯用
print(models.Book.objects.aggregate(Max('price')),Min('price'),Sum('price'),Count('price'))

分組查詢

annotate

'''
    分組查詢,一般和聚合函數一塊兒使用
    '''
# 1. 統計每一本書的 書名和對應的做者個數
print(models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num'))

# 2. 統計每各出版社賣的最便宜的書的價格
print(models.Publish.objects.annotate(book_num=Min('book__price')).values('name','book_num'))

# 3. 按照指定的字段進行分組
print(models.Publish.objects.values('name').annotate(max_price=Max('book__price')).values('name','max_price'))

# 4. 統計不止一個做者的圖書
# 首先拿到書對應的做者數,再篩選出大於一的圖書,做者個數
print(models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num'))

# 5. 查詢每一個做者出的書的總價格
print(models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price'))

F與Q查詢

'''
    F 查詢
    '''
from django.db.models import F,Q

# 1. 查詢庫存數大於賣出數的書籍
print(models.Book.objects.filter(kucun_num__gt=F('maichu_num')).values('title'))

# 2. 將全部書的價格都上漲100塊
models.Book.objects.all().update(price=F('price')+100)

# 3. 將全部書的名字後面都加上 後綴名
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title'),Value('新款')))

'''
    Q 查詢
    '''
# 1. 查詢書籍名是三國演義或者 庫存數是500的書籍
print(models.Book.objects.filter(title='三國演義',kucun_num=500))   # 默認是and的關係
print(models.Book.objects.filter(Q(title='三國演義') | Q(kucun_num=500)))   # 用了 | 就是or的關係
print(models.Book.objects.filter(~Q(title='三國演義') | Q(kucun_num=500)))   # 用了 | 就是or的關係

'''
    Q對象高級用法
'''
q = Q()
q.connector = 'or'  # 默認是and,能夠改爲or
q.children.append(('title','三國演義'))
q.children.append(('kucun_num',500))
print(models.Book.objects.filter(q))

ORM事務

還記得在Mysql數據庫中的事務操做嗎?

在MySQL中只有使用Innodb數據庫引擎的數據庫或表才支持使用事務

事務必須知足4個條件(ACID):

  • 原子性:一個事務中的全部操做,要麼所有執行,要麼所有回滾,中間不會結束在任何一個環節。
  • 一致性:在事務開始和事務結束以後,數據不會出錯
  • 隔離性:數據庫容許多個併發事務同時對數據進行讀寫和修改,每一個事務相互隔離
  • 持久性:事務處理結束後,對數據的修改是永久的
from django.db import transaction

with transaction.atomic():
    # 在縮進的代碼中書寫數據庫的操做
    # 該縮進下的全部代碼,都是一個事務
    pass


# 對整個view視圖開啓事務
@transaction.atomic
def index(request):
    //ORM操做
    return ....

例子

1.建立一個項目,新建一個APP(基礎操做,這裏再也不贅述)

2.經過ORM建立生成表

from django.db import models

class UserInfo(models.Model):
    username = models.CharField("用戶",max_length=32)
    balance = models.CharField("餘額",max_length=32)

注意啊:踩過的坑,涉及金融計算,涉及小數啊,要求特別精確的,咱們用字符串存儲。

若是是金融計算的話,咱們用一個decimal來進行計算。

3.咱們給數據庫加兩條數據,用來模擬兩個用戶之間的轉帳

4.配置URL

5.建立對應的視圖函數

from django.shortcuts import render,HttpResponse
from app01 import models
from django.db import transaction
from django.db.models import F

def index(request):
    try:
        with transaction.atomic():
            models.UserInfo.object.filter(id=1).update(balance=F("balance")-100)
            models.UserInfo.object.filter(id=2).update(balance=F("balance")+100)
    except Exception as e:
        return HttpResponse("出現錯誤<%s>"%str(e))
    return HttpResponse("執行成功")

當咱們訪問index的時候,會進行一次轉帳操做

6.如今,咱們讓他報錯

from django.shortcuts import render,HttpResponse
from app01 import models
from django.db import transaction
from django.db.models import F

def index(request):
    try:
        with transaction.atomic():
            models.UserInfo.object.filter(id=1).update(balance=F("balance")-100)
            raise 一個錯誤
            models.UserInfo.object.filter(id=2).update(balance=F("balance")+100)
    except Exception as e:
        return HttpResponse("出現錯誤<%s>"%str(e))
    return HttpResponse("執行成功")

咱們再次查看數據庫文件,若是沒有數據的原子性操做,咱們第一條sql執行完報錯,那錢確定是減去了

可是,咱們進行的是原子性的操做,你會發現錢沒有減誒。

完美,沒毛病

數據庫中的三大範式

範式(Normal Form),縮寫NF,規範化形式,簡稱範式。

目的是增長數據有效性,減小數據冗餘,提升存儲效率

  • 1NF:數據庫中的每個字段,必須是不可拆分的最小單位。
  • 2NF:表中全部字段都必須有意義,一個表只描述某一個事物
  • 3NF:表中不能有其餘表中存在的、存儲相同信息的字段,一般是經過外鍵去創建關聯,外鍵約束

第一範式(1NF)

數據庫中的每個字段,必須是不可拆分的最小單位。

即一個字段就表示一個意思,表中不能同時有2個字段來表示同一個意思

正例:

根據業務需求來合理使用行政區域

反例:

其中 address 能夠再分爲省、市、地區(縣)、街道、詳細地址,違反了第一範式。

第二範式(2NF)

表中全部字段都必須有意義,一個表只描述某一個事物

主鍵存在的意義就是惟一的標識表中的某一條記錄,若是某一列和該行記錄不要緊,也就不必存在。

反例:

此表中,天氣(weather字段)和用戶沒啥關係,也就不存在依賴關係,所不符合 第二範式。正確的作法應)該刪除此列,若有其餘須要可單獨存在一張表中。

第三範式(3NF)

表中不能有其餘表中存在的、存儲相同信息的字段,一般是經過外鍵去創建關聯,外鍵約束

反例:

上面是一個訂單表,字段從左至右以此是:訂單id、買家id、買家名稱、買家性別、買家年齡、訂單狀態。其中字段buyer_name、buyer_gender、buyer_age 是依賴於字段 buyer_info_id,違反 第二範式。

正例:

訂單表

img

買家信息表

img

數據庫五大約束

  • 主鍵約束(Primary Key):非空惟一,例如 將UserId做爲主鍵
  • 惟一約束(Unique):惟一,能夠空,但只能有一個,例如 身份證號惟一,由於每一個人的都不同
  • 檢查約束(Check):對該列數據的範圍、格式的限制(如:年齡、性別),例如 對年齡加以限定 20-40歲之間
  • 默認約束(Default):該數據的默認值,例如 若是地址不填 默認爲「地址不詳」
  • 外鍵約束(Foreign Key):須要創建兩表間的關係,例如 創建外鍵
相關文章
相關標籤/搜索