国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

通過demo學習OpenStack開發所需的基礎知識 -- 數據庫(1)

warnerwu / 2485人閱讀

摘要:另外,項目在單元測試中使用的是的內存數據庫,這樣開發者運行單元測試的時候不需要安裝和配置復雜的數據庫,只要安裝好就可以了。而且,數據庫是保存在內存中的,會提高單元測試的速度。是實現層的基礎。項目一般會使用數據庫來運行單元測試。

OpenStack中的關系型數據庫應用

OpenStack中的數據庫應用主要是關系型數據庫,主要使用的是MySQL數據庫。當然也有一些NoSQL的應用,比如Ceilometer項目。就SQL數據庫本身的應用而言,OpenStack的項目和其他項目并沒有什么區別,也是采用ORM技術對數據進行增刪改查而已。

本文的重點是講解OpenStack項目中對關系型數據庫的應用的基礎知識,更多的是涉及ORM庫的使用。對于數據庫的安裝和配置,需要讀者自己查找一下MySQL的教程,如果只是為了驗證ORM的相關知識,也可以使用sqlite數據庫。

數據庫的選擇

OpenStack官方推薦的保存生產數據的是MySQL數據庫,在devstack項目(這個項目用于快速搭建OpenStack開發環境)中也是安裝了MySQL數據庫。不過,因為OpenStack的項目中沒有使用特定的只有在MySQL上才能用的功能,而且所采用的ORM庫SQLAlchemy也支持多種數據庫,所以理論上選擇PostgreSQL之類的數據庫來替代MySQL也是可行的。

另外,OpenStack項目在單元測試中使用的是sqlite的內存數據庫,這樣開發者運行單元測試的時候不需要安裝和配置復雜的MySQL數據庫,只要安裝好sqlite3就可以了。而且,數據庫是保存在內存中的,會提高單元測試的速度。

ORM的選擇 什么是ORM

ORM的全稱是Object-Relational Mapping,即對象關系映射,是一種利用編程語言的對象來表示關系數據庫中的數據的技術,其更形式化的定義可以參考Wiki頁面Orject-relational mapping。簡單的說,ORM就是把數據庫的一張表和編程語言中的一個對象對應起來,這樣我們在編程語言中操作一個對象的時候,實際上就是在操作這張表,ORM(一般是一個庫)負責把我們對一個對象的操作轉換成對數據庫的操作。

Python中的ORM實現

一般來說,各種主流語言都有自己的ORM實現,一般來說也不只一種,比較出名的有Java的Hibernate,Ruby on Rails的ORM,C++的ODB等。在Python中也存在多種ORM的實現,最著名的兩種是Django的Model層的ORM實現,以及SQLAlchemy庫。這兩種ORM實現基本上是Python中ORM的事實上的標準,如果你寫Django應用,那么你就用Django自帶的實現;不然,你就可以選擇SQLAlchemy庫。

OpenStack基本上都是Python項目,所以在OpenStack中,ORM主要是使用了SQLAlchemy庫(Keystone, Nova, Neutron等);不過使用了Django的Horizon項目(面板)還是使用了Django自帶的ORM實現。本文主要是講解OpenStack中如何使用SQLAlchemy庫,這個也是開發OpenStack項目的最基本知識。

SQLAlchemy SQLAlchemy簡介

SQLAlchemy項目是Python中最著名的ORM實現,不僅在Python項目中也得到了廣泛的應用,而且對其他語言的ORM有很大的影響。OpenStack一開始選擇這個庫,也是看中了它足夠穩定、足夠強大的特點。

SQLAlchemy項目的官網是http://www.sqlalchemy.org/,目前該項目最新的版本是1.0.11,1.0系列是今年剛發的,0.9系列應該還是應用最廣泛的版本。對于一般的應用來說,0.9系列和1.0系列差別不大。

關于SQLAlchemy的學習

我個人覺得SQLAlchemy的學習難度會比Django的Model層難一些,因為一個最簡單的例子也會有一些不太直觀的地方,對于沒用過的人來說,會比較難以理解。不過SQLAlchemy官網整理了一些比較不錯的入門教程,是一個比較好的學習起點:Tutorials。另外,官方的Reference其實是一個很好的教程,講了很多基本的概念,有助于理解SQLAlchemy的庫的使用。Reference的地址是:http://docs.sqlalchemy.org/en/rel_1_0/,還可以直接下載PDF版本。我個人建議大家直接閱讀Reference即可,閱讀順序就按照PDF文件的章節編排順序進行。雖然這個文檔很長,但是我最后發現這么做是最節約時間的。

SQLAlchemy的架構

先讓我們來看一下SQLAlchemy這個庫的總體架構,如下圖(圖來自官網)所示:

SQLAlchemy這個庫分為兩層:

上面這層是ORM層,為用戶提供ORM接口,即通過操作Python對象來實現數據庫操作的接口。

下面這層是Core層,這層包含了Schema/Types, SQL Expression Language, Engine這三個部分:

SQL Expression Language是SQLAlchemy中實現的一套SQL表達系統,主要是實現了對SQL的DML(Data Manipulation Language)的封裝。這里實現了對數據庫的SELECT、DELETE、UPDATE等語句的封裝。SQL Expression Language是實現ORM層的基礎。

Schema/Types這部分主要是實現了對SQL的DDL(Data Definition Language)的封裝。實現了Table類用來表示一個表,Column類用來表示一個列,也是實現了將數據庫的數據類型映射到Python的數據類型。上面的SQL Expression Language的操作對象就是這里定義的Table。

Engine實現了對各種不同的數據庫客戶端的封裝和調度,是所有SQLAlchemy應用程序的入口點,要使用SQLAlchemy庫來操作一個數據庫,首先就要有一個Engine對象,后續的所有對數據庫的操作都要通過這個Engine對象來進行。下圖是官方文檔中的Engine位置的描述圖:

Pool是Engine下面的一個模塊,用來管理應用程序到數據庫的連接。

Dialect是Engine下的另一個模塊,用來對接不同的數據庫驅動(即DBMS客戶端),這些驅動要實現DBAPI接口。

最后,SQLAlchemy還要依賴各個數據庫驅動的DBAPI接口來實現對數據庫服務的調用。DBAPI是Python定義的數據庫API的實現規范,具體見PEP0249。

上面簡單的總結了SQLAlchemy的架構,希望大家能夠大概了解一下SQLAlchemy,在后面介紹一些相關概念時,能夠知道這個概念是屬于整個架構的哪個部分。

Dialect和數據庫客戶端

上面提到了Dialect是用來對接不同的數據庫驅動的,它主要負責將SQLAlchemy最后生成的數據庫操作轉換成對數據庫驅動的調用,其中會處理一些不同數據庫和不同DBAPI實現的差別。這個部分一般是SQLAlchemy的開發者關心的內容,如果你只是使用SQLAlchemy來操作數據庫,那么可以不用關心這個部分。不過我們還是要來了解一下SQLAlchemy支持的和OpenStack相關的數據庫驅動。

MySQL

OpenStack項目主要是使用MySQL,之前一直都在使用MySQL-Python驅動,因為這個驅動足夠成熟和穩定。不過這個情況正在轉變,有如下兩個原因:

MySQL-Python不支持Python3,而OpenStack正在轉換到Python3的過程中,所以這個驅動最終是要放棄的。

MySQL-Python是用C語言寫的,不支持eventlet庫的monkey-patch操作,無法被eventlet庫轉換成異步操作,所以使用了eventlet庫的到OpenStack項目在使用MySQL數據庫時,都是進行同步的串行操作,有性能損失。

為了解決這個問題,社區發起了一次對新驅動的評估,主要是評估PyMySQL驅動:PyMySQL Evaluation。這個評估還在社區的郵件列表發起了好幾次討論,到目前為止的結果是:如果使用Python 2.7,那么繼續使用MySQL-Python這個驅動,否則就使用PyMySQL這個驅動。PyMySQL驅動是使用純Python寫的,不僅支持Python3而且可以支持eventlet的異步。

SQLite3

OpenStack項目一般會使用SQLite3數據庫來運行單元測試。OpenStack在Python2.7下會使用pysqlite驅動,不過這個驅動和標準庫中的sqlite3模塊是一樣的,也就是Python內置了SQLite3的驅動,你無需選擇其他的驅動。

SQLAlchemy的基本概念和使用

使用SQLAlchemy大體上分為三個步驟:連接到數據庫,定義數據模型,執行數據操作。

連接到數據庫

在你的應用可以使用數據庫前,你要先定義好數據庫的連接,包括數據庫在哪里,用什么賬號訪問等。所有的這些工作都是通過Engine對象來進行的(記得上面提到的Engine了么?)。

數據庫URL

SQLAlchemy使用URL的方式來指定要訪問的數據庫,整個URL的具體格式如下:

dialect+driver://username:password@host:port/database

其中,dialect就是指DBMS的名稱,一般可選的值有:postgresql, mysql, sqlite等。driver就是指驅動的名稱,如果不指定,SQLAlchemy會使用默認值。database就是指DBMS中的一個數據庫,一般是指通過CREATE DATABASE語句創建的數據庫。其他的參數就不言而喻了。dialect和driver參數有很多選擇,具體的可以參考官方文檔:Database URLs

創建Engine對象

確定了要連接的數據庫信息后,就可以通過create_engine函數來創建一個Engine對象了。

from sqlalchemy import create_engine

engine = create_engine("sqlite://:memory:")

create_engine函數還支持以下幾個參數:

connect_args:一個字典,用來自定義數據庫連接的參數,比如指定客戶端使用的字符編碼。

pool_sizemax_overflow:指定連接池的大小。

poolclass:指定連接池的實現

echo:一個布爾值,用來指定是否打印執行的SQL語句到日志中。

還有很多其他的參數,可以參考官方文檔:Engine Configuration。

一般來說,Engine對象會默認啟用連接池,會根據不同的dialect來選擇不同的默認值。一般來說,你是不用考慮連接池的配置的,默認情況都配置好了。想了解關于連接池的更多內容,請查看官方文檔:Connection Pooling。

使用Engine對象

一般來說,應用程序的代碼是不直接使用Engine對象的,而是把Engine對象交給ORM去使用,或者創建session對象來使用。不過,我們還是來簡單看一下Engine對象能做什么事情。

應用程序可以調用Engine對象的connect()方法來獲得一個到數據庫的連接對象;然后可以在這個連接對象上調用execute()來執行SQL語句,調用begin()、commit()、rollback()來執行事務操作;調用close()來關閉連接。Engine對象也有一些快捷方法來直接執行上述操作,避免了每次都要調用connect()來獲取連接這種繁瑣的代碼,比如engine.execute(), with engine.begin()等。

定義數據模型

有了數據庫連接后,我們就可以來定義數據模型了,也就是定義映射數據庫表的Python類。在SQLAlchemy中,這是通過Declarative的系統來完成的。

Declarative系統

根據官方文檔的描述,SQLAlchemy一開始是采用下面這種方式來定義ORM的:

首先定義一個映射類,這個類是數據庫表在代碼中的對象表示,這類的類屬性是很多Column類的實例。

然后定義一個Table對象,這里的Table就是上面提到的在Schema/Types模塊中的一個類,用來表示一個數據庫中的表。

調用sqlalchemy.orm.mapper函數把步驟1中定義的類映射到步驟2中定義的Table。

上面這種方式稱為Classical Mappings,看起來好麻煩啊。所以就有了Declarative系統。這個系統就是一次完成這三個步驟,你只需要定義步驟1中的類即可。這也是現在在SQLAlchemy中使用ORM的方式,無需在使用過去這種麻煩的方法。

要使用Declarative系統,你需要為所有映射類創建一個基類,這個基類用來維護所有映射類的元信息。

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
定義映射類

現在我們可以開始創建映射類了。假設我們在數據庫中有一個表Person,這個表有兩個列,分別是id和name,那么我們創建的映射類如下:

from sqlalchemy import Column, Integer, String

# 這里的基類Base是上面我們通過declarative_base函數生成的
class Person(Base):
    __tablename__ = "person"

    id = Column(Interger, primary_key=True)
    name = Column(String(250), nullable=False)

這樣我們就定義了一個映射類Person,后續我們可以通過操作這個類的實例來實現對數據庫表person的操作。在我們的映射類中,我們使用__tablename__屬性來指定該映射類所對應的數據庫表,通過Column類實例的方式來指定數據庫的字段。這里,讀者可能會問:我如何能知道Column都能支持哪些類型呢?這個查看官方文檔獲得:Column And Data Types。

因為我們使用了Declarative系統,所以雖然我們自己沒有定義Table對象,但是Declarative系統幫我們做了,并且幫我們調用了mapper函數。因此,當我們定義好一個表的映射類后,這個類的__table__屬性就保存了該映射類所映射的Table對象:

In [6]: Person.__table__
Out[6]: Table("person", MetaData(bind=None),
    Column("id", Integer(), table=, primary_key=True, nullable=False),
    Column("name", String(length=250), table=, nullable=False), schema=None)

定義映射類是我們使用ORM的最主要的功能之一,不僅可以指定單表的映射,還能夠指定表之間的關系。由于篇幅限制,我們在本文就不展開講了。

Schema和Metadata

關于Table對象,我們上面也提到了,它屬于SQLAlchemy的core層的Schema/Types這個部分。SQLAlchemy中的Schema可以理解為和DDL相關的一套體系,它告訴SQLAlchemy的其他部分,數據庫中的表是如何定義的。這個相當于我們在MySQL中使用describe命令,或者在PostgreSQL中使用d命令。

SQLAlchemy中通過schema metadata來實現上面說的Schema。Schema metadata,官方文檔中也稱為database metadata,簡稱為metadata,是一個容器,其中包含了和DDL相關的所有信息,包括Table, Column等對象。當SQLAlchemy要根據映射類生成SQL語句時,它會查詢metadata中的信息,根據信息來生成SQL語句。

為了要讓metadata可以工作,我們需要把DDL的相關信息放到metadata中。如果你注意看上面Person.__table__的輸出,就會發現Table類的第二個參數就是一個Metadata實例,也就是說,我們需要在定義Table的時候就把DDL信息放到metadata中。如果是是用classical mapping的方式,我們需要先創建一個metadata實例,然后每次創建一個Table對象的時候就把metadata傳遞進去。從寫代碼的角度來說,這個方式沒有什么問題,也不算麻煩;問題是我們在使用ORM的過程中,幾乎不會用到metadata,metadata基本上是給SQLAlchemy用的,對于用戶來說metadata提供的接口只能用來創建表和刪除表,這種操作的頻率遠低于查詢操作。

好在Declarative系統則幫我們把這些都做好了。當我們通過declarative_base()生成一個基類Base的時候,這個基類就已經包含了一個metadata實例,后面基于Base定義映射類都會被自動加入到這個metadata中。我們可以通過Base.metadata來訪問這個metadata實例。

說了這么多關于metadata的內容,簡單總結一下:metadata是schema在SQLAlchemy中的實現,包含了DDL的信息,SQLAlchemy中的其他部分需要依賴于metadata中的信息,一般用戶很少使用metadata。

很少用?那說這么多是做啥?主要是讓讀者可以理解下面這個語句的原理:

Base = declarative_base()

# 基于Base定義映射類

Base.metadata.create_all(engine)

最后這行代碼是我們最常用到metadata的地方:創建所有的表。我們告訴create_all使用哪個engine,它就會生成所有的CREATE TABLE語句,并且通過engine發送到數據庫上執行。這個在單元測試的時候很有用。你可以執行一下下面的代碼來觀察輸出:

from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine


Base = declarative_base()


class Person(Base):
    __tablename__ = "person"

    id = Column(Integer, primary_key=True)
    name = Column(String(250), nullable=False)


engine = create_engine("sqlite:///:memory:", echo=True)


Base.metadata.create_all(engine)

輸出結果如下:

...
2016-01-06 09:56:03,600 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("person")
2016-01-06 09:56:03,601 INFO sqlalchemy.engine.base.Engine ()
2016-01-06 09:56:03,602 INFO sqlalchemy.engine.base.Engine
CREATE TABLE person (
        id INTEGER NOT NULL,
        name VARCHAR(250) NOT NULL,
        PRIMARY KEY (id)
)

2016-01-06 09:56:03,603 INFO sqlalchemy.engine.base.Engine ()
2016-01-06 09:56:03,603 INFO sqlalchemy.engine.base.Engine COMMIT

關于Metadata的更多信息,請查看官方文檔:Schema Definition Language。

會話

會話(session)是我們通過SQLAlchemy來操作數據庫的入口。我們前面有介紹過SQLAlchemy的架構,session是屬于ORM層的。Session的功能是管理我們的程序和數據庫之間的會話,它利用Engine的連接管理功能來實現會話。我們在上文有提到,我們創建了Engine對象,但是一般不直接使用它,而是把它交給ORM去使用。其中,通過session來使用Engine就是一個常用的方式。

要是用session,我們需要先通過sessionmaker函數創建一個session類,然后通過這個類的實例來使用會話,如下所示:

from sqlalchemy.orm import sessionmaker

DBSession = sessionmaker(bind=engine)
session = DBSession()

我們通過sessionmakerbind參數把Engine對象傳遞給DBSession去管理。然后,DBSession實例化的對象session就能被我們使用了。

CRUD

CRUD就是CREATE, READ, UPDATE, DELETE,增刪改查。這個也是SQLAlchemy中最常用的功能,而且都是通過上一小節中的session對象來使用的。我們這簡單的介紹一下這四個操作,后面會給出官方文檔的位置。

Create

在數據庫中插入一條記錄,是通過session的add()方法來實現的,你需要先創建一個映射類的實例,然后調用session.add()方法,然后調用session.commit()方法提交你的事務(關于事務,我們下面會專門講解):

new_person = Person(name="new person")
session.add(new_person)
session.commit()
Delete

刪除操作和創建操作差不多,是把一個映射類實例傳遞給session.delete()方法。

Update

更新一條記錄需要先使用查詢操作獲得一條記錄對應的對象,然后修改對象的屬性,再通過session.add()方法來完成更新操作。

Read

查詢操作,一般稱為query,在SQLAlchemy中一般是通過Query對象來完成的。我們可以通過session.query()方法來創建一個Query對象,然后調用Query對象的眾多方法來完成查詢操作。

事務

使用session,就會涉及到事務,我們的應用程序也會有很多事務操作的要求。當你調用一個session的方法,導致session執行一條SQL語句時,它會自動開始一個事務,直到你下次調用session.commit()或者session.rollback(),它就會結束這個事務。你也可以顯示的調用session.begin()來開始一個事務,并且session.begin()還可以配合Python的with來使用。

會話, CRUD, 事務的小結

上面關于session, CRUD和事務的內容寫的比較少,因為這些功能的內容很多,而且官方文檔也寫得很全面,本文就不做一些重復說明了。我們會在下一篇文章中通過webdemo的代碼來看看如何使用這些功能。

Session的文檔

官方文檔中關于CRUD操作的教程

Session中的事務管理

總結

本文介紹了OpenStack中和數據庫相關的一些知識,重點講解了SQLAlchemy這個庫的基本概念和架構。下一篇文章,我們會通過demo來實際項目中如何使用SQLAlchemy。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/45410.html

相關文章

  • 通過demo學習OpenStack開發需的基礎知識 -- API服務(1)

    摘要:通過,也就是通過各個項目提供的來使用各個服務的功能。通過使用的方式是由各個服務自己實現的,比如負責計算的項目實現了計算相關的,負責認證的項目實現了認證和授權相關的。的服務都是使用的方式來部署的。 使用OpenStack服務的方式 OpenStack項目作為一個IaaS平臺,提供了三種使用方式: 通過Web界面,也就是通過Dashboard(面板)來使用平臺上的功能。 通過命令行,也就...

    Jason_Geng 評論0 收藏0
  • 通過demo學習OpenStack開發需的基礎知識 -- 單元測試

    摘要:本文將進入單元測試的部分,這也是基礎知識中最后一個大塊。本文將重點講述和中的單元測試的生態環境。另外,在中指定要運行的單元測試用例的完整語法是。中使用模塊管理單元測試用例。每個項目的單元測試代碼結構可 本文將進入單元測試的部分,這也是基礎知識中最后一個大塊。本文將重點講述Python和OpenStack中的單元測試的生態環境。 單元測試的重要性 github上有個人畫了一些不同語言的學...

    douzifly 評論0 收藏0
  • 通過demo學習OpenStack開發需的基礎知識 -- 軟件包管理

    摘要:不幸的是,在軟件包管理十分混亂,至少歷史上十分混亂。的最大改進是將函數的參數單獨放到一個的文件中這些成為包的元數據。基于的版本號管理。的版本推導這里重點說明一下基于的版本號管理這個功能。開發版本號的形式如下。 為什么寫這個系列 OpenStack是目前我所知的最大最復雜的基于Python項目。整個OpenStack項目包含了數十個主要的子項目,每個子項目所用到的庫也不盡相同。因此,對于...

    blastz 評論0 收藏0
  • 通過demo學習OpenStack開發需的基礎知識 -- 數據(2)

    摘要:在實際項目中,這么做肯定是不行的實際項目中不會使用內存數據庫,這種數據庫一般只是在單元測試中使用。接下來,我們將會了解中單元測試的相關知識。 在上一篇文章,我們介紹了SQLAlchemy的基本概念,也介紹了基本的使用流程。本文我們結合webdemo這個項目來介紹如何在項目中使用SQLAlchemy。另外,我們還會介紹數據庫版本管理的概念和實踐,這也是OpenStack每個項目都需要做的...

    mingzhong 評論0 收藏0
  • 通過demo學習OpenStack開發需的基礎知識 -- API服務(4)

    摘要:到這里,我們的服務的框架已經搭建完成,并且測試服務器也跑起來了。上面的代碼也就可以修改為再次運行我們的測試服務器,就可以返現返回值為格式了。我們先來完成利用來檢查返回值的代碼方法的第一個參數表示返回值的類型這樣就完成了的返回值檢查了。 上一篇文章說到,我們將以實例的形式來繼續講述這個API服務的開發知識,這里會使用Pecan和WSME兩個庫。 設計REST API 要開發REST AP...

    meislzhua 評論0 收藏0

發表評論

0條評論

warnerwu

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<