#sqlalchemy之create_engine和session
orm
實質上,一個O/R Mapping會為你生成DAL。(即為數據訪問層(Data Access Layer)。其功能主要是負責數據庫的訪問。)用O/R Mapping保存,刪除,讀取對象,O/R Mapping負責生成SQL,你只需要關心對象就好。
一般的ORM包括以下四部分:
- 一個對持久類對象進行CRUD操作的API;// crud:增刪查改
- 一個語言或API用來規定與類和類屬性相關的查詢;
- 一個規定mapping metadata的工具;
- 一種技術可以讓ORM的實現同事務對象一起進行dirty checking, lazy association fetching以及其他的優化操作
SQLAlchemy介紹
Python中最有名的ORM架構就是SQLAlchemy,我們主要就是來學習SQLAlchemy的使用
初始化連接
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
self.engine = create_engine(conn['conn_str'],
pool_size=16,
pool_pre_ping=True)
self.session = sessionmaker(bind=self.engine)
create_engine()用來初始化數據庫連接。SQLAlchemy用一個字符串表示連接信息:
'數據庫類型+數據庫驅動名稱://用戶名:口令@機器地址:端口號/數據庫名'
數據庫連接池的使用
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session
from models import Student,Course,Student2Course
engine = create_engine(
"mysql+pymysql://root:123456@127.0.0.1:3306/s9day120?charset=utf8",
max_overflow=0, # 超過連接池大小外最多創建的連接
pool_size=5, # 連接池大小
pool_timeout=30, # 池中沒有線程最多等待的時間,否則報錯
pool_recycle=-1 # 多久之后對線程池中的線程進行一次連接的回收(重置)
)
SessionFactory = sessionmaker(bind=engine)
session = scoped_session(SessionFactory)
def task():
""""""
# 方式一:
"""
# 查詢
# cursor = session.execute('select * from users')
# result = cursor.fetchall()
# 添加
cursor = session.execute('INSERT INTO users(name) VALUES(:value)', params={"value": 'wupeiqi'})
session.commit()
print(cursor.lastrowid)
"""
# 方式二:
"""
# conn = engine.raw_connection()
# cursor = conn.cursor()
# cursor.execute(
# "select * from t1"
# )
# result = cursor.fetchall()
# cursor.close()
# conn.close()
"""
# 將連接交還給連接池
session.remove()
from threading import Thread
for i in range(20):
t = Thread(target=task)
t.start()
轉自http://www.cnblogs.com/lianggege123/articles/9210147.html
session 是ORM和db交互的方式
- 包裝了engine的連接
- 包裝了對象的identity map(類似cache, 保存了由表名和主鍵確定的唯一對象列表)
- 包裝了transaction
使用sessionmaker創建session
sessionmaker類保證創建出同樣配置的session. 應當全局被使用一次.
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///:memory:')
Session = sessionmaker(bind=engine)
session = Session()
Session狀態
https://stackoverflow.com/questions/8645250/how-to-close-sqlalchemy-connection-in-mysql
http://docs.sqlalchemy.org/en/latest/orm/session_state_management.html
一個實例在session中可能有以下狀態:
Transient
Pending
Persiste
Deleted
Detached
session.identity_map保存了一個WeakInstanceDict
key是database_identity(model的class, primary_key); value是InstanceState
Expunge:
將對象從session中移除,
sending persistent instances to the detached state, and pending instances to the transient state
對象實例會有一個dict對象保存屬性, 這些屬性類似緩存.
對象過期的時候(比如commit之后, 由於不知道事務的執行情況), dict內容會作廢, 再次訪問對象實例的屬性, 會觸發lazy load. 從數據庫加載這些屬性. 這個時候如果session已經close就會報錯.
可以在commit之前, 用expunge, 將對象實例從session移除. 這是對象實例可以正常使用. 但是無法加載未加載的屬性, 也無法加載expired的屬性.
mysql gone away
http://docs.sqlalchemy.org/en/latest/faq/connections.html?highlight=gone%20away
http://docs.sqlalchemy.org/en/latest/core/pooling.html#pool-disconnects
The primary cause of this error is that the MySQL connection has timed out and has been closed by the server. The MySQL server closes connections which have been idle a period of time which defaults to eight hours. To accommodate this, the immediate setting is to enable the create_engine.pool_recycle setting
For the more general case of accommodating database restarts and other temporary loss of connectivity due to network issues, connections that are in the pool may be recycled in response to more generalized disconnect detection techniques.
這時有兩種方式解決
- 悲觀方式: 每次執行語句前先執行select
1 或者通過pre_ping參數
engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)
- 樂觀方式: 執行失敗后重試
from sqlalchemy import create_engine, exc
e = create_engine(...)
c = e.connect()
try:
# suppose the database has been restarted.
c.execute("SELECT * FROM table")
c.close()
except exc.DBAPIError, e:
# an exception is raised, Connection is invalidated.
if e.connection_invalidated:
print("Connection was invalidated!")
# after the invalidate event, a new connection
# starts with a new Pool
c = e.connect()
c.execute("SELECT * FROM table")
轉自(https://www.jianshu.com/p/96e393afd721
添加點web里的session,對比一下
Cookie
cookie是瀏覽器保存在用戶電腦上的一小段文本,用來保存用戶在網站上的必要的信息。Web頁面或服務器告訴瀏覽器按照一定的規范存儲這些信息,並且在以后的所有請求中,這些信息就會自動加在http請求頭中發送給服務器,服務器根據這些信息判斷不同的用戶。並且cookie本身是安全的。
比如:
Cookie: name=value; name1=value1; name2=value2/pre>
Session
session的作用和cookie差不多,也是用來解決Http協議不能維持狀態的問題。但是session只存儲在服務器端的,不會在網絡中進行傳輸,所以較cookie來說,session相對安全一些。但是session是依賴cookie的,當用戶訪問某一站點時,服務器會為這個用戶產生唯一的session_id,並把這個session_id以cookie的形式發送到客戶端,以后的客戶端的所有請求都會自動攜帶這個cookie(前提是瀏覽器支持並且沒有禁用cookie)。
禁用cookie時如何使用session
有些時候,為了安全瀏覽器會禁用cookie,這時可以用傳參的方式將session_id發送到服務器,session可以照常工作.