1. 程式人生 > >4月16日 python學習總結 DBUtils模塊、orm 和 cookie、session、token

4月16日 python學習總結 DBUtils模塊、orm 和 cookie、session、token

用戶名 可用 繼續 打開 基於 動態 編號 身份認證 The

一、DBUtils模塊

介紹

The DBUtils suite is realized as a Python package containing two subsets of modules, one for use with arbitrary DB-API 2 modules, the other one for use with the classic PyGreSQL module.

The dependencies of the modules in the universal DB-API 2 variant are as indicated in the following diagram:

技術分享圖片

The dependencies of the modules in the classic PyGreSQL variant are similar:

使用PyGreSQL模塊實現了對PostgreSQL數據庫的操作

技術分享圖片

DBUtils是一套Python數據庫連接池包,並允許對非線程安全的數據庫接口進行線程安全包裝。DBUtils來自Webware for Python。

DBUtils提供兩種外部接口:
    PersistentDB :提供線程專用的數據庫連接,並自動管理連接。
    PooledDB :提供線程間可共享的數據庫連接,並自動管理連接。

實測證明 PersistentDB 的速度是最高的,但是在某些特殊情況下,數據庫的連接過程可能異常緩慢,而此時的PooledDB則可以提供相對來說平均連接時間比較短的管理方式。

另外,實際使用的數據庫驅動也有所依賴,比如SQLite數據庫只能使用PersistentDB作連接池。

功能
SteadyDB.py:用於穩定數據庫連接

PooledDB.py:連接池

PersistentDB.py:維持持續的數據庫連接(持續性連接)

SimplePooledDB.py:簡單連接池

SimplePooledDB :

DBUtils.SimplePooledDB 是一個非常簡單的數據庫連接池實現。他比完善的 PooledDB 模塊缺少很多功能。 DBUtils.SimplePooledDB 本質上類似於 MiscUtils.DBPool 這個Webware的組成部分。你可以把它看作一種演示程序。

SteadyDB:

DBUtils.SteadyDB 是一個模塊實現了”強硬”的數據庫連接,基於DB-API 2建立的原始連接。一個”強硬”的連接意味著在連接關閉之後,或者使用次數操作限制時會重新連接。

一個典型的例子是數據庫重啟時,而你的程序仍然在運行並需要訪問數據庫,或者當你的程序連接了一個防火墻後面的遠程數據庫,而防火墻重啟時丟失了狀態時。

一般來說你不需要直接使用 SteadyDB 它只是給接下來的兩個模塊提供基本服務, PersistentDB 和 PooledDB 。

PersistentDB:

DBUtils.PersistentDB 實現了強硬的、線程安全的、頑固的數據庫連接,使用DB-API 2模塊。

當一個線程首次打開一個數據庫連接時,一個連接會打開並僅供這個線程使用。當線程關閉連接時,連接仍然持續打開供這個線程下次請求時使用這個已經打開的連接。連接在線程死亡時自動關閉。

簡單的來說 PersistentDB 嘗試重用數據庫連接來提高線程化程序的數據庫訪問性能,並且他確保連接不會被線程之間共享。

因此, PersistentDB 可以在底層DB-API模塊並非線程安全的時候同樣工作的很好,並且他會在其他線程改變數據庫會話或者使用多語句事務時同樣避免問題的發生。

PooledDB

DBUtils.PooledDB 實現了一個強硬的、線程安全的、有緩存的、可復用的數據庫連接,使用任何DB-API 2模塊。

PooledDB 可以在不同線程之間共享打開的數據庫連接。這在你連接並指定 maxshared 參數,並且底層的DB-API 2接口是線程安全才可以,但是你仍然可以使用專用數據庫連接而不在線程之間共享連接。除了共享連接以外,還可以設立一個至少 mincached 的連接池,並且最多允許使用 maxcached 個連接,這可以同時用於專用和共享連接池。當一個線程關閉了一個非共享連接,則會返還到空閑連接池中等待下次使用。

如果底層DB-API模塊是非線程安全的,線程鎖會確保使用 PooledDB 是線程安全的。所以你並不需要為此擔心,但是你在使用專用連接來改變數據庫會話或執行多命令事務時必須小心。

該選擇哪一個?

PersistentDB 和 PooledDB 都是為了重用數據庫連接來提高性能,並保持數據庫的穩定性。

所以選擇何種模塊,可以參考上面的解釋。 PersistentDB 將會保持一定數量的連接供頻繁使用。在這種情況下你總是保持固定數量的連接。如果你的程序頻繁的啟動和關閉線程,最好使用 PooledDB 。後面將會提到更好的調整,尤其在使用線程安全的DB-API 2模塊時。

當然,這兩個模塊的接口是很相似的,你可以方便的在他們之間轉換,並查看哪個更好一些。

官方指南:https://cito.github.io/w4py-olde-docs/Webware/DBUtils/Docs/UsersGuide.html

使用

連接池對象只初始化一次,一般可以作為模塊級代碼來確保。 PersistentDB的連接例子:

import DBUtils.PersistentDB
persist=DBUtils.PersistentDB.PersistentDB(dbpai=MySQLdb,maxusage=1000,**kwargs)
這裏的參數dbpai指使用的底層數據庫模塊,兼容DB-API的。maxusage則為一個連接最大使用次數,參考了官方例子。後面的**kwargs則為實際傳遞給MySQLdb的參數。

獲取連接: conn=persist.connection() 實際編程中用過的連接直接關閉 conn.close() 即可將連接交還給連接池。

PooledDB使用方法同PersistentDB,只是參數有所不同。

        • dbapi :數據庫接口
        • mincached :啟動時開啟的空連接數量
        • maxcached :連接池最大可用連接數量
        • maxshared :連接池最大可共享連接數量
        • maxconnections :最大允許連接數量
        • blocking :達到最大數量時是否阻塞
        • maxusage :單個連接最大復用次數
        • setsession :用於傳遞到數據庫的準備會話,如 [”set name UTF-8″] 。

  PersistentDB:為每個線程創建一個連接,線程即使調用了close方法,也不會關閉,只是把連接重新放到連接池,供自己線程再次使用。當線程終止時,連接自動關閉

  PooledDB:創建一批連接到連接池,供所有線程共享使用。

技術分享圖片
from DBUtils.PersistentDB import PersistentDB
import pymysql
POOL = PersistentDB(
    creator=pymysql,  # 使用鏈接數據庫的模塊
    maxusage=None,  # 一個鏈接最多被重復使用的次數,None表示無限制
    setsession=[],  # 開始會話前執行的命令列表。
    ping=0,
    # ping MySQL服務端,檢查是否服務可用。
    closeable=False,
    # 如果為False時, conn.close() 實際上被忽略,供下次使用,再線程關閉時,才會自動關閉鏈接。如果為True時, conn.close()則關閉鏈接,那麽再次調用pool.connection時就會報錯,因為已經真的關閉了連接(pool.steady_connection()可以獲取一個新的鏈接)
    threadlocal=None,  # 本線程獨享值得對象,用於保存鏈接對象,如果鏈接對象被重置
    host=127.0.0.1,
    port=3306,
    user=root,
    password=123456,
    database=test,
    charset=utf8
)

def func():
    conn = POOL.connection(shareable=False)
    cursor = conn.cursor()
    cursor.execute(select * from user)
    result = cursor.fetchall()
    print(result)
    cursor.close()
    conn.close()
if __name__ == __main__:

    func()
PersistentDB 技術分享圖片
import pymysql

from DBUtils.PooledDB import PooledDB
POOL = PooledDB(
    creator=pymysql,  # 使用鏈接數據庫的模塊
    maxconnections=6,  # 連接池允許的最大連接數,0和None表示不限制連接數
    mincached=2,  # 初始化時,鏈接池中至少創建的空閑的鏈接,0表示不創建
    maxcached=5,  # 鏈接池中最多閑置的鏈接,0和None不限制
    maxshared=3,  # 鏈接池中最多共享的鏈接數量,0和None表示全部共享。PS: 無用,因為pymysql和MySQLdb等模塊的 threadsafety都為1,所有值無論設置為多少,_maxcached永遠為0,所以永遠是所有鏈接都共享。
    blocking=True,  # 連接池中如果沒有可用連接後,是否阻塞等待。True,等待;False,不等待然後報錯
    maxusage=None,  # 一個鏈接最多被重復使用的次數,None表示無限制
    setsession=[],  # 開始會話前執行的命令列表。
    ping=0,
    # ping MySQL服務端,檢查是否服務可用。
    host=127.0.0.1,
    port=3306,
    user=root,
    password=123456,
    database=test,
    charset=utf8
)


def func():
    # 檢測當前正在運行連接數的是否小於最大鏈接數,如果不小於則:等待或報raise TooManyConnections異常
    # 否則
    # 則優先去初始化時創建的鏈接中獲取鏈接 SteadyDBConnection。
    # 然後將SteadyDBConnection對象封裝到PooledDedicatedDBConnection中並返回。
    # 如果最開始創建的鏈接沒有鏈接,則去創建一個SteadyDBConnection對象,再封裝到PooledDedicatedDBConnection中並返回。
    # 一旦關閉鏈接後,連接就返回到連接池讓後續線程繼續使用。
    conn = POOL.connection()

    # print(th, ‘鏈接被拿走了‘, conn1._con)
    # print(th, ‘池子裏目前有‘, pool._idle_cache, ‘\r\n‘)

    cursor = conn.cursor()
    cursor.execute(select * from user)
    result = cursor.fetchall()
    print(result)
    conn.close()

if __name__ == __main__:

    func()
PooledDB

  

  cmd下載安裝DBUtils模塊: easy_install -U DBUtils

二、orm

ORM全稱“Object Relational Mapping”,即對象-關系映射,就是把關系數據庫的一行映射為一個對象,也就是一個類對應一個表,這樣,寫代碼更簡單,不用直接操作SQL語句。當我們需要對數據庫進行操作時,勢必需要通過連接數據、調用sql語句、執行sql語句等操作,ORM將數據庫中的表,字段,行與我們面向對象編程的類及其方法,屬性等一一對應,即將該部分操作封裝起來,程序猿不需懂得sql語句即可完成對數據庫的操作。

要編寫一個ORM框架,所有的類都只能動態定義,因為只有使用者才能根據表的結構定義出對應的類來,使用 metaclass 。

 

1、 在實例化一個user對象的時候,可以user=User(name=‘lqz‘,password=‘123‘)

2 、也可以 user=User()

    user[‘name‘]=‘lqz‘
    user[‘password‘]=‘123‘
3 、也可以 user=User()

    user.name=‘lqz‘
    user.password=‘password‘
前兩種,可以通過繼承字典dict來實現,第三種,用getattr和setattr

__getattr__ 攔截點號運算。當對未定義的屬性名稱和實例進行點號運算時,就會用屬性名作為字符串調用這個方法。如果繼承樹可以找到該屬性,則不調用此方法
__setattr__會攔截所有屬性的的賦值語句。如果定義了這個方法,self.arrt = value 就會變成self,__setattr__("attr", value).這個需要註意。當在__setattr__方法內對屬性進行賦值是,不可使用self.attr = value,因為他會再次調用self,__setattr__("attr", value),則會形成無窮遞歸循環,最後導致堆棧溢出異常。應該通過對屬性字典做索引運算來賦值任何實例屬性,也就是使用self.__dict__[‘name‘] = value

具體實現參考:https://blog.csdn.net/u013411246/article/details/80340978

三、cookie、session、token

session

  session的中文翻譯是“會話”,當用戶打開某個web應用時,便與web服務器產生一次session。服務器使用session把用戶的信息臨時保存在了服務器上,用戶離開網站後session會被銷毀。這種用戶信息存儲方式相對cookie來說更安全,可是session有一個缺陷:如果web服務器做了負載均衡,那麽下一個操作請求到了另一臺服務器的時候session會丟失。

cookie

  cookie是保存在本地終端的數據。cookie由服務器生成,發送給瀏覽器,瀏覽器把cookie以kv形式保存到某個目錄下的文本文件內,下一次請求同一網站時會把該cookie發送給服務器。由於cookie是存在客戶端上的,所以瀏覽器加入了一些限制確保cookie不會被惡意使用,同時不會占據太多磁盤空間,所以每個域的cookie數量是有限的。

cookie的組成有:名稱(key)、值(value)、有效域(domain)、路徑(域的路徑,一般設置為全局:"\")、失效時間、安全標誌(指定後,cookie只有在使用SSL連接時才發送到服務器(https))。下面是一個簡單的js使用cookie的例子:

用戶登錄時產生cookie:

document.cookie = "id="+result.data[‘id‘]+"; path=/";

document.cookie = "name="+result.data[‘name‘]+"; path=/";

document.cookie = "avatar="+result.data[‘avatar‘]+"; path=/";

使用到cookie時做如下解析:

var cookie = document.cookie;var cookieArr = cookie.split(";");var user_info = {};for(var i = 0; i < cookieArr.length; i++) {

user_info[cookieArr[i].split("=")[0]] = cookieArr[i].split("=")[1];

}

$(‘#user_name‘).text(user_info[‘ name‘]);

$(‘#user_avatar‘).attr("src", user_info[‘ avatar‘]);

$(‘#user_id‘).val(user_info[‘ id‘]);

token

token的意思是“令牌”,是用戶身份的驗證方式,最簡單的token組成:uid(用戶唯一的身份標識)、time(當前時間的時間戳)、sign(簽名,由token的前幾位+鹽以哈希算法壓縮成一定長的十六進制字符串,可以防止惡意第三方拼接token請求服務器)。還可以把不變的參數也放進token,避免多次查庫

cookie 和session的區別

1、cookie數據存放在客戶的瀏覽器上,session數據放在服務器上。

2、cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙
考慮到安全應當使用session。

3、session會在一定時間內保存在服務器上。當訪問增多,會比較占用你服務器的性能
考慮到減輕服務器性能方面,應當使用COOKIE。

4、單個cookie保存的數據不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。

5、所以個人建議:
將登陸信息等重要信息存放為SESSION
其他信息如果需要保留,可以放在COOKIE中

token 和session 的區別

session 和 oauth token並不矛盾,作為身份認證 token安全性比session好,因為每個請求都有簽名還能防止監聽以及重放攻擊,而session就必須靠鏈路層來保障通訊安全了。如上所說,如果你需要實現有狀態的會話,仍然可以增加session來在服務器端保存一些狀態

App通常用restful api跟server打交道。Rest是stateless的,也就是app不需要像browser那樣用cookie來保存session,因此用session token來標示自己就夠了,session/state由api server的邏輯處理。 如果你的後端不是stateless的rest api, 那麽你可能需要在app裏保存session.可以在app裏嵌入webkit,用一個隱藏的browser來管理cookie session.

Session 是一種HTTP存儲機制,目的是為無狀態的HTTP提供的持久機制。所謂Session 認證只是簡單的把User 信息存儲到Session 裏,因為SID 的不可預測性,暫且認為是安全的。這是一種認證手段。 而Token ,如果指的是OAuth Token 或類似的機制的話,提供的是 認證 和 授權認證是針對用戶,授權是針對App 。其目的是讓 某App有權利訪問 某用戶 的信息。這裏的 Token是唯一的。不可以轉移到其它 App上,也不可以轉到其它 用戶 上。 轉過來說Session 。Session只提供一種簡單的認證,即有此 SID,即認為有此 User的全部權利。是需要嚴格保密的,這個數據應該只保存在站方,不應該共享給其它網站或者第三方App。 所以簡單來說,如果你的用戶數據可能需要和第三方共享,或者允許第三方調用 API 接口,用 Token 。如果永遠只是自己的網站,自己的 App,用什麽就無所謂了。

token就是令牌,比如你授權(登錄)一個程序時,他就是個依據,判斷你是否已經授權該軟件;cookie就是寫在客戶端的一個txt文件,裏面包括你登錄信息之類的,這樣你下次在登錄某個網站,就會自動調用cookie自動登錄用戶名;session和cookie差不多,只是session是寫在服務器端的文件,也需要在客戶端寫入cookie文件,但是文件裏是你的瀏覽器編號.Session的狀態是存儲在服務器端,客戶端只有session id;而Token的狀態是存儲在客戶端。

4月16日 python學習總結 DBUtils模塊、orm 和 cookie、session、token