上篇文章提到了,最近在用 Python 做一个网站。除了 Tornado ,主要还用到了 SQLAlchemy。这篇就是介绍我在使用 SQLAlchemy 的过程中,学到的一些知识。首先说下,由于最新的 0.8 版还是开发版本,因此我使用的是 0.79 版,API 也许会有些不同。
因为我是搭配 MySQL InnoDB 使用,所以使用其他数据库的也不能完全照搬本文。
接着就从安装开始介绍吧,以 Debian/Ubuntu 为例(请确保有管理员权限):
- MySQL
apt-get install mysql-server
apt-get install mysql-client
apt-get install libmysqlclient15-dev - python-mysqldb
apt-get install python-mysqldb - easy_install
wget http://peak.telecommunity.com/dist/ez_setup.py
python ez_setup.py - MySQL-Python
easy_install MySQL-Python - SQLAlchemy
easy_install SQLAlchemy
如果是用其他操作系统,遇到问题就 Google 一下吧。我是在 Mac OS X 上开发的,途中也遇到些问题,不过当时没记下来……
值得一提的是我用了 MySQL-Python 来连 MySQL,因为不支持异步调用,所以和 Tornado 不是很搭。不过性能其实很好,因此以后再去研究下其他方案吧……
装好后就可以开始使用了:
1 2 3 4 5 6 7 |
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker DB_CONNECT_STRING = 'mysql+mysqldb://root:123@localhost/ooxx?' engine = create_engine(DB_CONNECT_STRING, echo=True) DB_Session = sessionmaker(bind=engine) session = DB_Session() |
这里的 DB_CONNECT_STRING 就是连接数据库的路径。“mysql+mysqldb”指定了使用 MySQL-Python 来连接,“root”和“123”分别是用户名和密码,“localhost”是数据库的域名,“ooxx”是使用的数据库名(可省略),“charset”指定了连接时使用的字符集(可省略)。
create_engine() 会返回一个数据库引擎,echo 参数为 True 时,会显示每条执行的 SQL 语句,生产环境下可关闭。
sessionmaker() 会生成一个数据库会话类。这个类的实例可以当成一个数据库连接,它同时还记录了一些查询的数据,并决定什么时候执行 SQL 语句。由于 SQLAlchemy 自己维护了一个数据库连接池(默认 5 个连接),因此初始化一个会话的开销并不大。对 Tornado 而言,可以在 BaseHandler 的 initialize() 里初始化:
1 2 3 4 5 6 |
class BaseHandler(tornado.web.RequestHandler): def initialize(self): self.session = models.DB_Session() def on_finish(self): self.session.close() |
对其他 Web 服务器来说,可以使用 sqlalchemy.orm.scoped_session,它能保证每个线程获得的 session 对象都是唯一的。不过 Tornado 本身就是单线程的,如果使用了异步方式,就可能会出现问题,因此我并没使用它。
拿到 session 后,就可以执行 SQL 了:
1 2 3 4 5 6 |
session.execute('create database abc') print session.execute('show databases').fetchall() session.execute('use abc') # 建 user 表的过程略 print session.execute('select * from user where id = 1').first() print session.execute('select * from user where id = :id', {'id': 1}).first() |
不过这和直接使用 MySQL-Python 没啥区别,所以就不介绍了;我还是喜欢 ORM 的方式,这也是我采用 SQLAlchemy 的唯一原因。
于是来定义一个表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
from sqlalchemy import Column from sqlalchemy.types import CHAR, Integer, String from sqlalchemy.ext.declarative import declarative_base BaseModel = declarative_base() def init_db(): BaseModel.metadata.create_all(engine) def drop_db(): BaseModel.metadata.drop_all(engine) class User(BaseModel): __tablename__ = 'user' id = Column(Integer, primary_key=True) name = Column(CHAR(30)) # or Column(String(30)) init_db() |
declarative_base() 创建了一个 BaseModel 类,这个类的子类可以自动与一个表关联。
以 User 类为例,它的 __tablename__ 属性就是数据库中该表的名称,它有 id 和 name 这两个字段,分别为整型和 30 个定长字符。Column 还有一些其他的参数,我就不解释了。
最后,BaseModel.metadata.create_all(engine) 会找到 BaseModel 的所有子类,并在数据库中建立这些表;drop_all() 则是删除这些表。
接着就开始使用这个表吧:
1 2 3 4 5 6 7 8 9 10 11 12 先说下,由于最新的 0.8 版还是开发版本,因此我使用的是 0.79 版,API 也许会有些不同。 因为我是搭配 MySQL InnoDB 使用,所以使用其他数据库的也不能完全照搬本文。 接着就从安装开始介绍吧,以 Debian/Ubuntu 为例(请确保有管理员权限):
如果是用其他操作系统,遇到问题就 Google 一下吧。我是在 Mac OS X 上开发的,途中也遇到些问题,不过当时没记下来…… 装好后就可以开始使用了:
这里的 DB_CONNECT_STRING 就是连接数据库的路径。“mysql+mysqldb”指定了使用 MySQL-Python 来连接,“root”和“123”分别是用户名和密码,“localhost”是数据库的域名,“ooxx”是使用的数据库名(可省略),“charset”指定了连接时使用的字符集(可省略)。
对其他 Web 服务器来说,可以使用 sqlalchemy.orm.scoped_session,它能保证每个线程获得的 session 对象都是唯一的。不过 Tornado 本身就是单线程的,如果使用了异步方式,就可能会出现问题,因此我并没使用它。 拿到 session 后,就可以执行 SQL 了:
不过这和直接使用 MySQL-Python 没啥区别,所以就不介绍了;我还是喜欢 ORM 的方式,这也是我采用 SQLAlchemy 的唯一原因。 于是来定义一个表:
declarative_base() 创建了一个 BaseModel 类,这个类的子类可以自动与一个表关联。 接着就开始使用这个表吧: |