文章目錄
Sqlalchemy And Flask-Sqlalchemy
使用sqlalchemy時,先搞明白:
- sqlalchemy和flask-sqlalchemy不相等。flask-sqlalchemy是一個flask的擴展,簡化了在flask中使用sqlalchemy的操作。
- sqlalchemy提供了高層orm,也提供了使用數據庫原生sql的底層功能。
sqlalchemy使用
db.create_all()
可以用來創建表,若表已存在,那麼其不會進行創建或者更新。但是在修改模型後要把改動應用到現有的數據庫中,粗暴的方式爲先刪除表,再重新創建。db.drop_all()
/db.create_all()
因此,可以用Django的那套orm來創建表,sqlalchemy只用來操作表內的數據。
事務操作(數據庫會話也成爲事務)
- 通過數據庫會話管理對數據庫所做的改動。sqlalchemy中用
db.session
標識db.session.add()
添加到會話db.session.flush()
刷新會話,這裏可以拿到對象的id,對應的數據已到數據庫緩存中,只是還未提交。db.session.commit()
提交會話
- 數據庫會話能保證數據庫的一致性。
- 提交操作使用原子方式把會話中的對象全部寫入數據庫。如果寫入的過程發生了錯誤,整個會話都會失效。(只要把相關的改動放在會話中提交,就能避免因部分更新導致的數據庫的不一致,就能完成事務的操作)
db.session.rollback()
數據庫會話的回滾。調用後,添加到數據庫會話的所有對象都會還原到他們在數據庫時的狀態。
db.session.flush
詳解
通過query可以拿到數據,執行mysql語句同理也可以,但是這個只限於在當前連接的緩存內體現,數據還未被持久化到數據庫文件。別的賬戶連接,是看不到這個數據的。也就是數據庫沒有這條數據,但是在緩存內是有這個數據的。
# TODO 試驗db.session.flush()
@ns.route('/test')
class test(Resource):
def get(self):
# 最後一個id是122
count_obj = dbm.TaskCount()
count_obj.date = '1111-11-11'
count_obj.total_count = 11
count_obj.complete_count = 11
count_obj.task_template_id = 646
db.session.add(count_obj)
db.session.flush()
logger.info(">>>>>>>>> flush_id >>>>>%s"%count_obj.id)
query_obj = dbm.TaskCount.query.filter_by(id=count_obj.id).first()
if query_obj:
logger.info(".....%s"%query_obj.id)
logger.info('......data..... %s'%query_obj.date)
temp_id = count_obj.id
query2 = db.session.execute("select * from patrol_inspect_task_count where id=:id", {'id': temp_id}).fetchall()
logger.info('******** query_2 ********* %s'%query2)
return 'yes!'
# 得到的結果(基於mysql的緩存,預提交機制autocommit機制的設置)
# flush可以拿到id
>>>>>>>>> flush_id >>>>>125
.....125
......data..... 1111-11-11
# 直接執行sql語句拿到的結果
******** query_2 ********* [(125, u'1111-11-11', 11, 11, 646)]
sqlalchemy注意點
1. filter_by(name='haha').count()
的坑
# 執行上述的count方式:
temp_count = dbm.PersonnelBlacklist.query.filter(text(sql_text)).params(**sql_params).count()
# sqlalchemy執行的sql爲:
"""轉化sql含義爲先搜索出所有sql對象,在統計所有數據對象的數量,當數據量大的時候,這樣會嚴重影響速度。"""
SELECT count(*) AS count_1
FROM (SELECT * FROM account_personnel_blacklist) AS anon_1
# 優化方式:
temp_count = db.session.query(func.count(dbm.PersonnelBlacklist.id)).\
filter(text(sql_text)).params(**sql_params).first()[0]
# 這樣轉化過來的sql爲:
# 直接執行搜索數量,數據量大的時候,提升回很明顯
SELECT count(account_personnel_blacklist.id) AS count_1
FROM account_personnel_blacklist LIMIT %(param_1)s
2.pagination_obj.items和pagination_obj.total
的弊端
-
得到pagination的分頁對象後<flask_sqlalchemy.Pagination object at 0x7fd7046df9d0>,內部有items用於獲取所有對象,total獲取總的數量(篩選條件下,不做分頁)
-
雖然得到的是一個對象,但想獲取到數據和總數量,這裏會隱式的執行兩條sql(一條用於查數據,一條用於查總數量)
-
如下的兩條(與上邊count的坑一致):
select * from account
select count(*) from account (select * from account) as temp_data
-
但但是上邊的操作,對coder比較友好,一行代碼即可搞定。若要優化好可以將獲取數據,獲取總數量(
select count(id) from account
)分成兩步精簡的sql進行執行