1. ホーム
  2. python

[解決済み] トランザクションとsqlalchemy

2022-03-01 15:11:40

質問

Python 3 の SQLAlchemy を使って、データベースに多数の(100k のオーダーで)レコードを挿入する方法を見つけようとしています。すべてはトランザクションを使うことを指します。しかし、それがどのように行われるのか、少し混乱しています。

いくつかのページでは、トランザクションを connection.begin() である場合と、他の場所では session.begin() そしてこのページ ここで と書いてあります。 session.create_transaction() が存在しない。

以下は、私がやろうとしていることです。

def addToTable(listOfRows):
    engine = create_engine('postgresql+pypostgresql:///%s' % db,echo = False)
    Session = sessionmaker(bind = engine)
    session = Session()
    table = myTable(engine,session)

    for row in listOfRows:
       table.add(row)
    table.flush() ### ideally there would be a counter and you flush after a couple of thousand records


class myTable:

    def __init__(self,engine,session):
       self.engine  = engine
       self.session = session
       self.transaction =createTransaction()# Create transaction code here

   def add(self,row):
       newRow = tableRow(row) ## This just creates a representation of a row in the DB
       self.transaction.add(newRow)
       self.transaction.flush()

   def flush(self):
       self.transaction.commit()

解決方法は?

SQLAlchemyの旅を続ける前に、両方のチュートリアルをやっておくことを強くお勧めします。これらは本当に有用で、多くの概念を説明しています。その後、次の本を読むことをお勧めします セッションを使用する というのも、セッションがこのすべてにどのように関わっているのかを説明しているからです。

あなたの問題に対しては、2つの解決策があります。ひとつはORMを使ったもの、もうひとつはCoreを使ったものです。前者はより簡単で、後者はより速いです。まず、簡単なほうを考えてみましょう。トランザクションは、すべてのステートメントを1つの操作にラップするためにのみ使用されます。つまり、もし何かが失敗したら、そのすべてを中止することができ、どこかに何かが残っているわけではありません。ですから、ほとんどの場合、トランザクションが必要ですが、トランザクションがなくても動作するでしょう。ここでは、最も手っ取り早い方法を紹介します。

with session.begin():
    session.add_all([tableRow(row) for row in listOfRows])

データによっては、SQLAlchemyがあなたの INSERT ステートメントを一度に複数回実行できるようにします。以下はその内容です。

  • を使用してトランザクションが開始されます。 session.begin
  • データが追加される (使用 add_all というループがありますが、複数の add でもよい)
  • セッションがコミットされます。ここで何か問題が発生した場合、トランザクションは中断され、あなたはエラーを修正することができます。

なぜなら SQLAlchemy はすべての ORM アルゴリズムを通過しなければならないので、いくらかオーバーヘッドを生む可能性があるからです。もしこれが一度だけのデータベースの初期化なら、ORM を避けることができます。その場合、ORM クラスを作る代わりに ( tableRow )、すべてのキーを持つ辞書を作成します(方法はデータによって異なります)。この場合も、コンテキスト・マネージャーを使用することができます。

with engine.begin() as connection:
    connection.execute(tableRow.__table__.insert().
                       values([row_to_dict(row) for row in listOfRows]))

この方が若干速くなる可能性が高いですが、利便性も低くなります。これは上記のセッションと同じように動作しますが、ORMではなくCoreからステートメントを構築する点が異なります。