Tornado中sqlalchemy使用

兩岸風景發表於2015-10-14

在學tornado的時候涉及以下資料庫操作,現在暫時使用mysql資料庫,所以選擇了一個比較好用的ORM工具sqlalchemy,順便記一下使用過程

安裝

首先安裝mysql

pip安裝必要的庫:pip install sqlalchemy

下載mysql-python驅動:
http://www.codegood.com/archives/129
如果是32位版本的windows選win32,如果是64的可以選擇amd64

配置

首先需要一個資料庫配置檔案

# -*- coding: utf-8 -*-
DB_HOST = `127.0.0.1`
# DB_HOST = `127.0.0.1`
DB_USER = `root`
# DB_USER = `root`
DB_PWD = ``
# DB_PWD = `084358`
DB_NAME = `my404`
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base() #create Base lei
engine = create_engine(`mysql://%s:%s@%s/%s?charset=utf8` %
                   (DB_USER, DB_PWD, DB_HOST, DB_NAME),
                 encoding=`utf-8`, echo=False,
                   pool_size=100, pool_recycle=10)
                   

這裡我寫了一個db.py檔案,目錄在tornado專案根目錄下的mod.databases下

接下來是一段類似於orm裡實體類部分的程式碼,我同樣放在了mod.databases下,名字為tables.py

from sqlalchemy import Column, String, Integer, VARCHAR,ForeignKey, Float 
from sqlalchemy.orm import relationship,backref
from db import engine,Base

class Article(Base):
    __tablename__ = `articles`
    user = Column(VARCHAR(20),primary_key = True)
    title = Column(VARCHAR(40))
    time = Column(VARCHAR(20))
    content = Column(VARCHAR(2000))

每個類對應一個表,上方匯入必要的庫和db裡的一些配置資訊,注意一定要設定一項為primary_key,不然在查詢時會報錯Could not assemble any primary key columns for mapped table

這就是大概需要配置的部分,如果需要用新的表就在tables.py裡面加入新的類就好了

使用

如下,在自己的main.py裡需要對定義的application裡面做一下資料庫的設定,通過self.db修改屬性來設定一些和資料庫相關的操作。但是具體其中的屬性還不太瞭解,就先放著了。

class Application(tornado.web.Application):

    def __init__(self):
        handlers = [
        (r"/", IndexHandler),
        ]
        settings = dict(
            debug=True,
            static_path=os.path.join(os.path.dirname(__file__),"static"),
            template_path=os.path.join(os.path.dirname(__file__), "templates")
        )
        tornado.web.Application.__init__(self, handlers, **settings)
        self.db = scoped_session(sessionmaker(bind=engine,
                                              autocommit=False, autoflush=True,
                                              expire_on_commit=False))

if __name__ == `__main__`:
    tornado.options.parse_command_line()
    Application().listen(options.port, address=`127.0.0.1`)
    tornado.ioloop.IOLoop.instance().start()

在具體的handler裡使用時如下

from tornado.httpclient import HTTPRequest, AsyncHTTPClient
from mod.databases.tables import Article
import tornado.web
import tornado.gen
import urllib

class DbHandler(tornado.web.RequestHandler):

    @property
    def db(self):
        return self.application.db

    def get(self):
        data = self.db.query(Article).all()
        for item in data:
            print item.content
            

一方面對使用的實體類要進行匯入,如

from mod.databases.tables import Article

另一方面db函式上方

@property

標註是python關於屬性的標註,有了這個標註就可以使用self.db來直接獲取連線物件,而不需要加上括號self.db(),看起來會比較直觀

查詢

具體的查詢語句就是

data = self.db.query(Article).all()

這裡我從資料庫裡取出資料後只把每一項的content列輸出了,並沒有進行其他操作。
其他的使用方法可以參考sqlalchemy的官方文件
http://docs.sqlalchemy.org/en/rel_1_0/or…

插入

new_user = User(user_email = email,user_name = name,user_psd = psd)
self.db.add(new_user)
self.db.commit()
self.db.close()#用完後關閉資料庫連線,否則可能 導致此次連線時間過長而未操作,資料庫連線超時的問題

需要注意的地方是commit函式,如果沒有commit,那麼self.db裡還是儲存著之前的資訊,這樣說似乎不太明白,但是我在使用的過程中發生了一個這樣的情景:
我搭建了一個小網站,可以用於註冊登入,在我註冊時我先檢測相關資訊是否合法,例如使用者名稱(郵箱)是否已存在:

user = self.db.query(User).filter(User.user_email == self.email).first()
if user!=None:
    表示使用者名稱已存在
    返回錯誤資訊
else:
    使用者名稱不存在,可以註冊
    new_user = User(user_email = email,user_name = name,user_psd = psd)
    self.db.add(new_user)
    self.db.commit()

但緊接著,我又做了一件沒有什麼必要做的事情(請不要吐槽,我只是這麼寫了一下,其實目的是檢測一下這個使用者是否在資料庫中存在了,然後返回註冊成功的資訊

user = self.db.query(User).filter(User.user_name == name).first()
if(user.user_email == email):
    self.db.commit()
    data["status"] = 200
    data["data"] = "Register Success"
    標記2
    self.write(data)
    
    

但是這麼做令我出現了一個麻煩
在我註冊成功後,我從資料庫中緊接著刪除了這個使用者,然後重新註冊,這時候他顯示這個使用者還是存在的…
在我將tornado的服務重啟後,用同樣的使用者名稱去註冊,發現這時候又不顯示該使用者存在了,於是註冊成功

之後我在標記2處加了一句self.db.commit()後這個問題就不再出現了。
一般我們還會採取的操作是
原因是因為self.db其實是sqlalchemy的scoped_session,他相當於未commit時有個快取,查詢結果也會快取在其中。於是雖然資料庫裡刪除了某使用者,但是在刪除之前我做了一次對這個使用者的查詢,導致self.db裡快取了這個使用者。所以下次他直接在快取裡找到了這個使用者。
重啟服務後快取清掉了,也就恢復正常和資料庫保持同步了…

具體的原因還得看看文件…如果有知道的同學歡迎指導啊=.=

相關文章