这个例子说明了我在构建的应用程序中遇到的一个谜。应用程序需要支持一个选项,允许用户在不实际向数据库提交更改的情况下运行代码。但是,当我添加此选项时,我发现即使我没有调用 commit()
方法,更改也会保存到数据库中。
我的具体问题可以在代码注释中找到。基本目标是更清楚地了解 SQLAlchemy 何时以及为何提交给数据库。
我的更广泛的问题是我的应用程序是否应该 (a) 使用全局 Session
实例,或者 (b) 使用全局 Session
类,从中可以获取特定实例实例化。基于这个例子,我开始认为正确答案是 (b)。是对的吗? 编辑:this SQLAlchemy documentation建议 (b) 是推荐的。
import sys
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key = True)
name = Column(String)
age = Column(Integer)
def __init__(self, name, age = 0):
self.name = name
self.age = 0
def __repr__(self):
return "<User(name='{0}', age={1})>".format(self.name, self.age)
engine = create_engine('sqlite://', echo = False)
Base.metadata.create_all(engine)
Session = sessionmaker()
Session.configure(bind=engine)
global_session = Session() # A global Session instance.
commit_ages = False # Whether to commit in modify_ages().
use_global = True # If True, modify_ages() will commit, regardless
# of the value of commit_ages. Why?
def get_session():
return global_session if use_global else Session()
def add_users(names):
s = get_session()
s.add_all(User(nm) for nm in names)
s.commit()
def list_users():
s = get_session()
for u in s.query(User): print ' ', u
def modify_ages():
s = get_session()
n = 0
for u in s.query(User):
n += 10
u.age = n
if commit_ages: s.commit()
add_users(('A', 'B', 'C'))
print '\nBefore:'
list_users()
modify_ages()
print '\nAfter:'
list_users()
最佳答案
tl;dr - 更新并未实际提交到数据库——它们是正在进行的未提交事务的一部分。
我对您对 create_engine() 的调用做了 2 处单独的更改。 (除了这一行,我完全按照发布的方式使用您的代码。)
第一个是
engine = create_engine('sqlite://', echo = True)
这提供了一些有用的信息。我不打算在这里发布完整的输出,但请注意,在 第二次调用 list_users() 之前,不会发出任何 SQL 更新命令:
...
After:
xxxx-xx-xx xx:xx:xx,xxx INFO sqlalchemy.engine.base.Engine.0x...d3d0 UPDATE users SET age=? WHERE users.id = ?
xxxx-xx-xx xx:xx:xx,xxx INFO sqlalchemy.engine.base.Engine.0x...d3d0 (10, 1)
...
这是一个线索,表明数据没有持久化,而是保存在 session 对象中。
我做的第二个改变是将数据库持久化到一个文件中
engine = create_engine('sqlite:///db.sqlite', echo = True)
再次运行脚本会提供与第二次调用 list_users() 之前相同的输出:
<User(name='A', age=10)>
<User(name='B', age=20)>
<User(name='C', age=30)>
但是,如果您现在打开我们刚刚创建的数据库并查询它的内容,您可以看到添加的用户已保存到数据库中,但年龄修改没有:
$ sqlite3 db.sqlite "select * from users"
1|A|0
2|B|0
3|C|0
因此,对 list_users() 的第二次调用是从 session 对象而不是数据库中获取其值,因为正在进行的事务尚未提交。为了证明这一点,请将以下行添加到脚本的末尾:
s = get_session()
s.rollback()
print '\nAfter rollback:'
list_users()
关于python - 为什么这个 SQLAlchemy 示例将更改提交到数据库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3998546/