a1.sqlalchemy-研究

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進行執行

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章