Quick Start¶
Install cx_Oracle_async¶
Supports python3.7 or later.
Install from PyPI:
pip instal cx_Oracle_async
Install Oracle Client¶
If you’re connecting to database which is on a different machine from python process , you need to setup a oracle instanct client module before you use this library. Check cx-Oracle’s installation guide for further information.
Basic Usage¶
All usage in cx_Oracle_async based on the session pool, cx_Oracle_async does not provide means you can setup a simple connection to database without pool manager.
Here’s a basic example:
import cx_Oracle_async
import asyncio
async def main():
oracle_pool = await cx_Oracle_async.create_pool(
host='localhost',
port='1521',
user='user',
password='password',
service_name='orcl',
min = 2,
max = 4,
)
async with oracle_pool.acquire() as connection:
async with connection.cursor() as cursor:
await cursor.execute("SELECT * FROM V$SESSION")
print(await cursor.fetchall())
await oracle_pool.close()
asyncio.run(main())
Or you may prefer to use makedsn
style to manage your token and server destinations:
async def main():
dsn = cx_Oracle_async.makedsn('localhost' , '1521' , service_name = 'orcl')
oracle_pool = await cx_Oracle_async.create_pool(
'username' ,
'password' ,
dsn,
)
...
You can use both context manager / non-context manager way to access your SessionPool()
, Connection()
, Cursor()
object , they will act the same in results.
from cx_Oracle_async import makedsn , create_pool
import asyncio
async def main():
dsn = makedsn('localhost' , '1521' , service_name = 'orcl')
pool_1 = await create_pool('username' , 'password' , dsn)
async with create_pool('username' , 'password' , dsn) as pool_2:
assert type(pool_1) == type(pool_2)
conn_1 = await pool_2.acquire()
async with pool_2.acquire() as conn_2:
assert type(conn_1) == type(conn_2)
cursor = await conn.cursor()
await cursor.execute("SELECT * FROM V$SESSION")
await pool_1.close()
asyncio.run(main())
Closing SessionPools¶
You can hardly run into close problem in normal use with the help of a context manager , however , if you’re using some kind of nested code structure , SessionPool.close()
may get cx_Oracle.DatabaseError: ORA-24422
which indicates there’s still some connection remaining activate when close
triggered. In this perticular situation , you may need to use SessionPool.close(force = True)
to ignore those error.
import cx_Oracle_async
import asyncio
async def solitary_fetching_thread(pool):
# Simulation of a long duration query.
async with pool.acquire() as conn:
async with conn.cursor() as cursor:
await cursor.execute("BEGIN DBMS_LOCK.SLEEP(10); END;")
async def main():
dsn = cx_Oracle_async.makedsn('localhost' , '1521' , service_name = 'orcl')
pool = await cx_Oracle_async.create_pool(
'username' ,
'password' ,
dsn,
)
loop = asyncio.get_running_loop()
loop.create_task(solitary_fetching_thread(pool))
await asyncio.sleep(2)
# If you're not using force == True (which is False by default)
# you'll get a exception of ORA-24422.
await pool.close(force = True)
asyncio.run(main())
It is noteworthy that although force = True
is set , main thread loop of pool.close()
will not continue untill all connection finished its query anyhow. In latest version of Oracle database (e.g. Oracle DB 19c) , you can use interrupt = True
to let every activate connection in sessionpool cancel its current qurey in order to get a quick return. However , DO NOT use this feature if you’re using a legacy version of Orace DB such as Oracle DB 11g , force cancel feature may cause connection no response and create a deadlock in your mainloop.
import cx_Oracle_async
import asyncio
from async_timeout import timeout
async def solitary_fetching_thread(pool):
# Simulation of a long duration query.
async with pool.acquire() as conn:
async with conn.cursor() as cursor:
await cursor.execute("BEGIN DBMS_LOCK.SLEEP(10); END;")
async def main():
dsn = cx_Oracle_async.makedsn('localhost' , '1521' , service_name = 'orcl')
pool = await cx_Oracle_async.create_pool(
'username' ,
'password' ,
dsn,
)
loop = asyncio.get_running_loop()
loop.create_task(solitary_fetching_thread(pool))
await asyncio.sleep(2)
async with timeout(2):
# This will not cause a asyncio.TimeoutError exception
# cause the long duration query is canceled.
await pool.close(force = True , interrupt = True)
asyncio.run(main())