2026年9月24日、Pythonでデータベースを扱うための定番ライブラリ、SQLAlchemyの2.1.0が公開されました。2023年に出た2.0以来の、機能追加をともなう大きな版です。
10月2日には修正版の2.1.3も出ており、すでにpip installで普通に入る状態になっています。手元のプロジェクトでSQLAlchemyを使っている方は、知らないうちに2.1へ上がっているかもしれません。
今回は、公式の移行ガイドにあたる、What's New in SQLAlchemy 2.1という文書をもとに、初心者がつまずきそうな変更を中心に見ていきます。
まずは何が変わったのかを整理しよう¶
変更点はとても多いので、最初に今回取り上げるものを表にまとめます。どれも、公式の移行ガイドに書かれている内容です。
| 変更 | 中身 | 影響を受けやすい人 |
|---|---|---|
| Pythonの対応範囲 | 3.10のサポートを外し、3.11以上が必須に | 古いPythonで動かしている人 |
| greenlet | 標準では入らなくなった | asyncioと組み合わせて使っている人 |
| autoflush | text()などで書いたSQLでも、実行前に必ずflushされる | 生のSQLとORMを混ぜて使っている人 |
| t-string | Python 3.14のテンプレート文字列でSQLを書ける | 新しい書き方を試したい人 |
| PostgreSQL | 標準のドライバーがpsycopg2からpsycopg(3)に | PostgreSQLを使っている人 |
SQLAlchemyそのものがまだよくわからない方は、先にこちらを読んでおくと話がつながります。【関連記事】PythonのSQLAlchemyとは?
Python 3.11以上が必須になった¶
いちばん影響が大きいのは、対応するPythonのバージョンです。SQLAlchemy 2.1は、Python 3.11以上でしか動きません。
移行ガイドによると、3.10は2026年8月の時点で外されました。10月に3.10のサポートが終わることを見越した判断です。
3.10のサポート終了については、先日の記事で詳しく取り上げました。【関連記事】Python 3.15の正式版は10月9日に延期、3.10はサポート終了へ
なぜ早めに外したのか¶
移行ガイドには、その理由も書かれています。1.4系と2.0系はそれぞれ約4年使われ、2.0系はPython 3.7から3.15までという長い範囲に対応し続ける必要がありました。
2.1系では、使われている期間中にPythonのバージョンを外さずに済むよう、最初から新しめのバージョンに絞ったそうです。ライブラリを長く保守する側の苦労がよくわかる説明ですね。
3.10のままpip install sqlalchemyを実行すると、2.1ではなく、3.10に対応した2.0系の最新版が入ります。エラーにはならないので、気づかないまま古い系列を使い続けることになる点に注意しましょう。
greenletが標準で入らなくなった¶
2つ目の変更は、インストールされるライブラリです。これまでSQLAlchemyを入れると、greenletという別のライブラリも一緒に入ることがありました。
greenletは、SQLAlchemyをasyncioと組み合わせて使うときに必要になる部品です。2.1からは、asyncioを使う人だけが追加で入れる形に変わりました。
実際に、新しい仮想環境に2.0系と2.1系をそれぞれ入れて比べてみました。
| 入れたもの | 一緒に入ったライブラリ |
|---|---|
| SQLAlchemy 2.0.54 | greenlet、typing_extensions |
| SQLAlchemy 2.1.3 | typing_extensions のみ |
asyncioと組み合わせている場合は、pip install "sqlalchemy[asyncio]"のように、asyncioの付いた形で入れ直してください。asyncioそのものについては、こちらで紹介しています。【関連記事】Pythonのasyncioとは?
私は10年ほどエンジニアとして開発に関わってきましたが、ライブラリの更新で、間接的に入っていた別のライブラリが消えて動かなくなるトラブルには何度も出会いました。動いていたのは、たまたま一緒に入っていたから、というケースは意外と多いものです。
text()でもautoflushが走るようになった¶
3つ目は、少し気づきにくい変更です。2.1では、Sessionのautoflushの動きが変わりました。
autoflushとは何か¶
Sessionにオブジェクトをaddしても、その時点ではまだデータベースに書き込まれていません。書き込むことをflushと呼び、クエリを実行する直前に自動でflushする仕組みをautoflushと呼びます。
2.0までは、このautoflushが走るのはselect()などのORMのクエリを実行したときだけでした。text()で書いた生のSQLを実行しても、flushされなかったのです。
2.0と2.1で結果が変わるコード¶
実際に、同じコードを2.0と2.1で動かして比べてみましょう。ユーザーを1人addしてから、text()とselect()でそれぞれ読み出します。
import sqlalchemy
from sqlalchemy import String, create_engine, select, text
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column
print("SQLAlchemy", sqlalchemy.__version__)
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(30))
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(User(name="hanako"))
# text() で書いた生のSQLを実行する
rows = session.execute(text("SELECT name FROM users")).all()
print("text()の結果:", rows)
print("select()の結果:", session.scalars(select(User.name)).all())
手元のPython 3.11で、2.0.54と2.1.3をそれぞれ入れて実行した結果です。まずは2.0.54です。
SQLAlchemy 2.0.54
text()の結果: []
select()の結果: ['hanako']
続いて2.1.3です。text()の結果が変わっているのがわかります。
SQLAlchemy 2.1.3
text()の結果: [('hanako',)]
select()の結果: ['hanako']
2.0では、text()の時点でまだflushされていないので、addしたはずのhanakoが見えません。2.1では、どんな書き方のSQLでも実行前に必ずflushされるようになり、結果がそろいました。
移行ガイドでは、この変更でセッションの動きがより一貫して予測しやすくなる、と説明されています。逆に言えば、2.0の動きを前提に書いたコードは、2.1で結果が変わるおそれがあります。
SQLiteを使った基本的なデータベース操作は、こちらで練習できます。【関連記事】PythonでSQLiteを使う方法
Python 3.14のt-stringでSQLを書ける¶
4つ目は、新しい書き方への対応です。2.1では、Python 3.14で加わったテンプレート文字列、通称t-stringを使ってSQLを組み立てるtstring()が追加されました。
t-stringは、PEP 750で定められた新しい文字列です。f-stringに似た見た目ですが、埋め込んだ値をすぐに文字列へ混ぜず、あとから安全に処理できる形で保持します。
移行ガイドに載っている例を引用します。Python 3.14以上でのみ動くコードです。
from sqlalchemy import tstring
user_id = 42
stmt = tstring(t"SELECT * FROM users WHERE id = {user_id}")
# renders: SELECT * FROM users WHERE id = :param_1
埋め込んだuser_idは、SQLの文字列に直接書き込まれず、バインドパラメーターとして渡されます。f-stringで同じことをすると、値がそのままSQLに混ざってしまい、SQLインジェクションの原因になりかねません。
f-stringでSQLを組み立てるのは危険、というのは昔からの鉄則です。t-stringなら、f-stringに近い書きやすさのまま、その危険を避けられます。
f-stringとの違いを知るには、まずf-stringをしっかり押さえておくのが近道です。【関連記事】Pythonのf-stringとは?
PostgreSQLの標準ドライバーも変わった¶
PostgreSQLを使っている方は、もう1つ注意があります。接続URLでドライバーを省略したときに使われるものが、psycopg2からpsycopg(バージョン3)に変わりました。
postgresql://で始まるURLのままだと、2.1ではpsycopgを探しにいきます。psycopg2しか入っていない環境では、URLをpostgresql+psycopg2://と明示すれば、これまでどおり使えます。
移行ガイドでは、ドライバーを明示するpostgresql+psycopg://の書き方がおすすめとされています。URLを見ただけでどのドライバーを使うかわかるので、迷いがなくなります。
上げる前にやっておきたいこと¶
最後に、2.0から2.1へ上げるときの確認ポイントを整理します。小さなプロジェクトなら、次の順番で確かめれば十分です。
| 順番 | 確認すること |
|---|---|
| 1 | 動かしているPythonが3.11以上か |
| 2 | asyncioと組み合わせているなら、sqlalchemy[asyncio]で入れているか |
| 3 | text()とORMを混ぜて使っている箇所で、結果が変わらないか |
| 4 | PostgreSQLの接続URLでドライバーを明示しているか |
| 5 | テストを2.1で一通り流して、警告やエラーが出ないか |
まだ上げる準備ができていないなら、requirements.txtなどでsqlalchemy<2.1と上限を決めておくのも1つの手です。準備ができたタイミングで、自分の意思で上げられます。
以前、バージョンの上限を書かずにいたせいで、ある朝のデプロイで突然大きな版に上がり、原因を探すのに半日かかったことがあります。上げるタイミングは自分で決めるようにしておくと、こうした事故は防げます。
まとめ¶
SQLAlchemy 2.1.0が2026年9月24日に公開され、10月2日には2.1.3まで進んでいます。Python 3.11以上が必須になり、greenletが標準で入らなくなり、text()でもautoflushが走るようになりました。
t-stringへの対応のように、これからのPythonを見据えた新機能も入っています。使っている方は、上の確認ポイントを参考に、自分のタイミングで移行を進めてください。
ここまでお読みいただきありがとうございました。