Fork from CSDN
基本概念
说到数据库,就离不开Session。Session的主要目的是建立与数据库的会话,它维护你加载和关联的所有数据库对象。它是数据库查询(Query)的一个入口。
在Sqlalchemy中,数据库的查询操作是通过Query对象来实现的。而Session提供了创建Query对象的接口。
Query对象返回的结果是一组同一映射(Identity Map)对象组成的集合。事实上,集合中的一个对象,对应于数据库表中的一行(即一条记录)。所谓同一映射,是指每个对象有一个唯一的ID。如果两个对象(的引用)ID相同,则认为它们对应的是相同的对象。
要完成数据库查询,就需要建立与数据库的连接。这就需要用到Engine对象。一个Engine可能是关联一个Session对象,也可能关联一个数据库表。
当然Session最重要的功能还是实现原子操作。
创建Session
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
some_engine = create_engine('nysql://username:password@localhost/mydb?charset=utf8')
ession = sessionmaker(bind=some_engine)
session = Session()
代码第4行创建一个Engine对象,我们提供的参数是数据库连接的url。
代码第6行通过sessionmaker方法创建了一个Session工厂。
代码第8行通过调用工厂方法来创建一个Session对象。
Session的生命期
Session通常在我们需要对数据库进行操作时创建。
一旦一个Session创建成功,我们在这个Session下完成多个事务(transaction)。
究竟何时创建和关闭session,不能一概而论。但是一个原则是session不应该在操作事务的方法中创建。
例如下面的方法定义就是不规范的。
class SomeThing(object):
def go(self):
session = Session()
try:
# Do something
session.commit()
except:
session.rollback()
raise
The correct code is here:
class SomeThing(object):
def go(self, session):
# Do something
def run_my_program():
session = Session()
try:
SomeThing().go(session)
session.commit()
except:
session.rollback()
raise
finally:
session.close()
Session Basics
- What does the Session do ?
In the most general sense, the** Session
establishes all conversations with the database** (建立与数据库之间的通信)and represents a “holding zone” for all the objects which you’ve loaded or associated with it during its lifespan(相当于“缓存区”,面向所有的加载的或者相关的对象). It provides the entry-point (指令变换点)to acquire a Query
object, __which sends queries to the database using the Session
object’s current database connection (通过当前session object的数据库连接发送query请求), __populating result rows into objects that are then stored in the Session
, (将存储在 Session 中的 result rows 迁移到 objects 中)inside a structure called the Identity Map - a data structure that maintains unique copies of each object, where “unique” means “only one object with a particular primary key”.
The Session
begins in an essentially stateless(无状态的) form. Once queries are issued or other objects are persisted with it, it requests a connection resource from an Engine
that is associated either with the Session
itself or with the mapped Table
objects being operated upon.(一个与Session关联或者与 Table 映射的数据库 engine是必须的) This connection represents an ongoing transaction, which remains in effect until the Session
is instructed to commit or roll back its pending state (这个连接表示一个不断进行的事务,它会一直起效直到 Session 被执行commit 或者回滚到之前的 pending 状态).
All changes to objects maintained by a Session
are tracked (所有由session维护,并对objects的改变,都会被追踪)- before the database is queried again or before the current transaction is committed, (在再一次查询数据库 或 当前事务被提交 之前), it flushes all pending changes to the database. This is known as the Unit of Work pattern.
Unit of work : A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work.
When using a Session
, it’s important to note that the objects which are associated with it are proxy objects(代理 objects) to the transaction being held by the Session
- there are a variety of events that will cause objects to re-access the database in order to keep synchronized (存在很多的事件会导致objects 重复连接数据库,为了保持同步性). It is possible to “detach” objects from a Session
, and to continue using them, though this practice has its caveats(警告). It’s intended that usually, you’d re-associate detached objects with another Session
when you want to work with them again, (所以需要通过其他的Session 重新联系已分发的objects,如果你想要重新使他们工作)so that they can resume their normal task of representing database state.
Getting a Session¶
Session
is a regular Python class which can be directly instantiated(直接实例化). However, to standardize how sessions are configured and acquired, the sessionmaker
class is normally used to create a top level Session
configuration which can then be used throughout an application without the need to repeat the configurational arguments(使用sessionmaker,无需重新配置session).
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# an Engine, which the Session will use for connection
# resources
some_engine = create_engine('postgresql://scott:tiger@localhost/') #数据库的链接
# create a configured "Session" class
Session = sessionmaker(bind=some_engine)
# create a Session
session = Session()
# work with sess
myobject = MyObject('foo', 'bar')
session.add(myobject)
session.commit()
Above, the sessionmaker
call creates a factory for us, which we assign to the name Session
This factory, when called, will create a new Session
object using the configurational arguments we’ve given the factory. In this case, as is typical, we’ve configured the factory to specify a particular Engine
for connection resources.
A typical setup will associate the sessionmaker with an Engine, so that each Session generated will use this Engine to acquire connection resources. (生成的每个 Session 都通过engine来获取连接资源) This association can be set up as in the example above, using the bind argument.
When you write your application, place the sessionmaker
factory at the global level(设置sessionmaker到全局层面). This factory can then be used by the rest of the application as the source of new Session
instances, keeping the configuration for how Session
objects are constructed in one place.
The sessionmaker
factory can also be used in conjunction with other helpers, which are passed a user-defined sessionmaker
that is then maintained by the helper. Some of these helpers are discussed in the section When do I construct a Session, when do I commit it, and when do I close it?.(sessionmaker还可以自定义)
Adding Additional Configuration to an Existing sessionmaker()
A common scenario is where the sessionmaker
is invoked (被调用)at module import time, however the generation of one or more Engine
instances to be associated with the sessionmaker
has not yet proceeded.(一个常见的情况是,sessionmaker通常在模块被导入时就被调用,但与sessionmaker耦合的engine还没有生成) For this use case, the sessionmaker
construct offers the sessionmaker.configure()
method, which will place additional configuration directives into an existing sessionmaker
that will take place when the construct is invoked(在construct被调用时,configure()会将额外的配置指令加入到已经存在的session-maker中):
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
# configure Session class with desired options
Session = sessionmaker()
# later, we create the engine
engine = create_engine('postgresql://...')
# associate it with our custom Session class
Session.configure(bind=engine)
# work with the session
session = Session()
Creating Ad-Hoc Session Objects with Alternate Arguments
For the use case where an application needs to create a new Session
with special arguments that deviate from what is normally used throughout the application, such as a Session
that binds to an alternate source of connectivity, or a Session
that should have other arguments such as expire_on_commit
established differently from what most of the application wants, specific arguments can be passed to the sessionmaker
factory’s sessionmaker.call()
method. These arguments will override(废除) whatever configurations have already been placed, such as below, where a new Session
is constructed against a specific Connection
:
# at the module level, the global sessionmaker,
# bound to a specific Engine
Session = sessionmaker(bind=engine)
# later, some unit of code wants to create a
# Session that is bound to a specific Connection
conn = engine.connect()
session = Session(bind=conn)
The typical rationale for the association of a Session
with a specific Connection
is that of a test fixture that maintains an external transaction - see Joining a Session into an External Transaction (such as for test suites) for an example of this.