3

在学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里缓存了这个用户。所以下次他直接在缓存里找到了这个用户。
重启服务后缓存清掉了,也就恢复正常和数据库保持同步了…

具体的原因还得看看文档…如果有知道的同学欢迎指导啊=.=


两岸风景
142 声望8 粉丝

I am NaOH


引用和评论

0 条评论