如何阻止sqlalchemy在select上创建事务?

时间:2016-09-01 17:43:41

标签: python transactions sqlalchemy

我的问题:

我有一个包含多行数据的文件。我想尝试将每一行插入我的数据库,但如果任何行有问题,我需要回滚整个工具包和kaboodle。但是我想跟踪实际的错误,而不是只是死在第一个有错误的记录上我可以这样说:

  

此文件中有42个错误。

Line 1 is missing a whirlygig.
Line 2 is a duplicate.
Line 5 is right out.

我尝试这样做的方式是使用事务,但是我有一个问题,SQLAlchemy在select上创建了隐式事务,显然我真的不明白sqlalchemy是如何使用事务的,因为我所做的一切似乎都不起作用我想要的方式。这是一些演示我问题的代码:

import sqlalchemy as sa
import logging
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
l = logging.getLogger('sqlalchemy.engine')
l.setLevel(logging.INFO)
l.addHandler(logging.StreamHandler())

engine = sa.create_engine('YOUR PG CONNECTION HERE')

Session = sessionmaker(bind=engine)
session = Session()
temp_metadata = sa.MetaData(schema='pg_temp')
TempBase = declarative_base(metadata=temp_metadata)


class Whatever(TempBase):
    __tablename__ = 'whatevs'
    id = sa.Column('id', sa.Integer, primary_key=True, autoincrement=True)
    fnord = sa.Column('fnord', sa.String, server_default=sa.schema.FetchedValue())
    quux = sa.Column('quux', sa.String)
    value = sa.Column('value', sa.String)


def insert_some_stuff(session, data):
    value = session.query(Whatever.value).limit(1).scalar()
    session.add(Whatever(quux=data, value='hi'))
    try:
        session.commit()
        errors = 0
    except sa.exc.IntegrityError:
        session.rollback()
        errors = 1
    return errors


with session.begin_nested():
    session.execute('''
        CREATE TABLE pg_temp.whatevs (
            id      serial
          , fnord   text not null default 'fnord'
          , quux    text not null
          , value   text not null
          , CONSTRAINT totally_unique UNIQUE (quux)
        );
        INSERT INTO pg_temp.whatevs (value, quux) VALUES ('something cool', 'fnord');
    ''')
    w = Whatever(value='something cool', quux='herp')
    session.add(w)


errors = 0
for q in ('foo', 'biz', 'bang', 'herp'):
    with session.begin_nested():
        errors += insert_some_stuff(session, q)
for row in session.query(Whatever).all():
    print(row.id, row.fnord, row.value)

我尝试了session.begin().begin(subtransactions=True)的各种组合,但它们都不起作用,或者只是看起来很奇怪,因为我提交的事务从未(明确) )开始了。

我可以阻止sqlalchemy在select上创建一个事务吗?或者我在这里遗漏了什么?有没有更好的方法来实现我想要的目标?

1 个答案:

答案 0 :(得分:1)

看起来好像是begin_nestedwith块。

  

begin_nested(),方式与使用频率较低的begin()方法相同...... - sqlalchemy docs

这让我相信begin_nested是首选。

def insert_some_stuff(session, data):
    try:
        with session.begin_nested():
            value = session.query(Whatever.value).limit(1).scalar()
            session.add(Whatever(quux=data, value='hi'))
        errors = 0
    except sa.exc.IntegrityError:
        errors = 1

    return errors

通过使用with块,它可以提供/回滚,而不是向后滚动太多。