SQLAlchemy作为一款强大而又实用的ORM框架,越来越频繁的出现在各类Python项目中。如果你是一名Python开发工程师,肯定可以熟练的写出SQLAlchemy的查询语句来满足自己的业务需求。然而,SQLAlchemy背后的知识你又了解多少呢?它是什么时候与数据库建立连接的呢?又是怎样的连接方式呢?SQLAlchemy中的Session与数据库的Transaction是一回事吗?如何优雅地管理SQLAlchemy的连接与事务呢?本文将结合SQLAlchemy文档解答这些问题。
为了方便展示,我在本地MySQL中创建了一张student表,同时打开MySQL的general-log来追踪MySQL的行为。
CREATE TABLE `student` (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '自增主键',
name STRING NOT NULL DEFAULT '' COMMENT '姓名',
primary key(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '学生表';
set global general_log=1;
同时在iPython中创建我们的ORM对象。
DeclarativeBase = declarative_base()
class StudentModel(DeclarativeBase):
__tablename__ = 'student'
id = Column(BigInteger, primary_key=True)
name = Column(String, default=u'')
连接
SQAlchemy通过create_engine创建Engine对象来实现数据库连接.
# DB_CONNECT_STRING = 'mysql+pymysql://root:[email protected]/test?charset=utf8'
engine = create_engine(DB_CONNECT_STRING, pool_size=5, max_overflow=2, pool_recycle=60, echo=True)
这里设置echo=True来显示所执行的SQL日志。
延时加载
执行create_engine后general-log和stdout并没有显示任何信息,因为SQLAlchemy到数据库的连接是延时加载的,只有真正需要建立连接时才会创建。The Engine, when first returned by create_engine(), has not actually tried to connect to the database yet; that happens only the first time it is asked to perform a task against the database.
调用connect方法建立连接:
connection = engine.connect()
此时general-log显示如下信息,表示真正建立了到数据库的连接,连接线程ID为22,除此之外,SQAlchemy会默认将数据库的autocommit设置为0,在查询时会隐式开始Transaction。
2018-11-27T13:52:48.695968Z 22 Connect [email protected] on test using TCP/IP
2018-11-27T13:52:48.701437Z 22 Query SET AUTOCOMMIT = 0
连接池
Engine对象维护着一个连接池pool,如果没有通过poolclass=NullPool来禁用连接池,在连接关闭后会被暂存在pool中,下次创建连接时会直接从pool中获取连接,如果从连接池中拿到的连接距离创建时间超过pool_recycle,Engine将会将此连接释放并创建新的连接。
在pool_recycle时间内调用close关闭连接,同时创建一个新连接:
connection.close()
connection2 = engine.connect()
general-log并没有新日志显示,查看MySQL的连接发现并没有新连接产生。
mysql> show processlist;
+----+------+-----------------+------+----