diff --git a/README.asyncpg.md b/README.asyncpg.md index 7c73fa8..5be0e6e 100644 --- a/README.asyncpg.md +++ b/README.asyncpg.md @@ -9,9 +9,81 @@ There is a customized version of the FastAPI SQL database tutorial for https://github.com/gordthompson/fastapi-tutorial-cockroachdb-async -### Database support for Alembic +### Default transaction isolation level -CockroachDB version 23.1 or later is required to work with Alembic. +Applications using asyncpg that were developed prior to CockroachDB's inclusion of +READ COMMITTED transaction isolation may operate on the assumption that the default +isolation level will be SERIALIZABLE. For example, + +```python +import asyncio + +from sqlalchemy.ext.asyncio import create_async_engine + + +async def async_main(): + engine = create_async_engine( + "cockroachdb+asyncpg://root@localhost:26257/defaultdb", + ) + async with engine.begin() as conn: + result = await conn.exec_driver_sql("select version()") + print(result.scalar().split("(")[0]) # CockroachDB CCL v23.2.4 + + result = await conn.exec_driver_sql("show transaction isolation level") + print(result.scalar()) # serializable + + +asyncio.run(async_main()) +``` + +With current versions of CockroachDB, the default transaction isolation level +**for asyncpg only** is now READ COMMITTED + +```python +import asyncio + +from sqlalchemy.ext.asyncio import create_async_engine + + +async def async_main(): + engine = create_async_engine( + "cockroachdb+asyncpg://root@localhost:26257/defaultdb", + ) + async with engine.begin() as conn: + result = await conn.exec_driver_sql("select version()") + print(result.scalar().split("(")[0]) # CockroachDB CCL v24.3.0 + + result = await conn.exec_driver_sql("show transaction isolation level") + print(result.scalar()) # read committed + + +asyncio.run(async_main()) +``` + +Applications that rely on the previous behavior will have to add `isolation_level="SERIALIZABLE"` +to their `create_async_engine()` call + +```python +import asyncio + +from sqlalchemy.ext.asyncio import create_async_engine + + +async def async_main(): + engine = create_async_engine( + "cockroachdb+asyncpg://root@localhost:26257/defaultdb", + isolation_level="SERIALIZABLE", + ) + async with engine.begin() as conn: + result = await conn.exec_driver_sql("select version()") + print(result.scalar().split("(")[0]) # CockroachDB CCL v24.3.0 + + result = await conn.exec_driver_sql("show transaction isolation level") + print(result.scalar()) # serializable + + +asyncio.run(async_main()) +``` ### Testing diff --git a/sqlalchemy_cockroachdb/provision.py b/sqlalchemy_cockroachdb/provision.py index 68e92bd..db7e616 100644 --- a/sqlalchemy_cockroachdb/provision.py +++ b/sqlalchemy_cockroachdb/provision.py @@ -6,7 +6,8 @@ def _cockroachdb_temp_table_keyword_args(cfg, eng): return {"prefixes": ["TEMPORARY"]} + @update_db_opts.for_db("cockroachdb") def _update_db_opts(db_url, db_opts, options): """Set database options (db_opts) for a test database that we created.""" - db_opts['isolation_level'] = 'SERIALIZABLE' \ No newline at end of file + db_opts["isolation_level"] = "SERIALIZABLE"