SQLAlchemy JDBCAPI
SQLAlchemy-JDBCAPI is a modern SQLAlchemy dialect that provides native DB-API 2.0 implementation for JDBC connections using JPype, and ODBC connections via pyodbc. It supports a wide range of databases including PostgreSQL, MySQL, SQL Server, Oracle, and many others, with features like automatic JDBC driver management. The current version is 2.2.1, and it maintains an active release cadence with frequent updates and new features such as full asyncio support.
Common errors
-
RuntimeError: No JVM shared library found. Please install a JDK or JRE and set JAVA_HOME.
cause JPype, used by sqlalchemy-jdbcapi, cannot locate a Java Virtual Machine (JVM) on your system.fixInstall a Java Development Kit (JDK) or Java Runtime Environment (JRE) (Java 8+ is recommended) and set the `JAVA_HOME` environment variable to point to its installation directory. -
jpype.JClass.JClassException: Class <driver_class_name> not found.
cause The JDBC driver class specified in your connection string (or the one automatically chosen) could not be loaded by the JVM, usually because the driver JAR file is missing or corrupted, or its path is incorrect.fixVerify that the necessary JDBC driver JAR file is available. If using automatic driver management, check network connectivity to Maven Central. If providing manually, ensure the JAR file is placed in a directory listed in `SQL_ALCHEMY_JDBCAPI_JVM_CLASSPATH` or specified via `jdbcapi.driver_path`. -
sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:jdbcapi+<driver_name>
cause SQLAlchemy cannot find the registered dialect for `jdbcapi+<driver_name>`. This typically happens if `sqlalchemy-jdbcapi` is not installed or incorrectly installed.fixEnsure `sqlalchemy-jdbcapi` is correctly installed: `pip install sqlalchemy-jdbcapi`. If using ODBC, make sure `pip install sqlalchemy-jdbcapi[pyodbc]` was used. -
sqlalchemy.exc.InterfaceError: (pyodbc.Error) ('01000', "[01000] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified (0) (SQLDriverConnect)")cause This error occurs when using the `jdbcapi+pyodbc` dialect and the underlying ODBC driver or DSN is not correctly configured on the system.fixEnsure `pyodbc` is installed (`pip install sqlalchemy-jdbcapi[pyodbc]`) and that your ODBC DSN or driver configuration on the operating system is valid for the specified database.
Warnings
- breaking Version 2.0.0 of `sqlalchemy-jdbcapi` introduced a complete rewrite of its core infrastructure, transitioning to a native DB-API 2.0 implementation built on JPype. This fundamentally changed how the dialect interacts with databases compared to 1.x versions.
- gotcha `sqlalchemy-jdbcapi` relies on `JPype` for JDBC connectivity, which requires a Java Virtual Machine (JVM) to be present and discoverable on the system. Common issues include `RuntimeError: No JVM shared library found` or `JClassException` for missing Java classes.
- gotcha The library automatically downloads JDBC drivers from Maven Central by default. This process can fail due to network restrictions (e.g., corporate proxies, firewalls), or if specific driver versions are required but not available or correctly resolved.
- gotcha Full asyncio support, including `AsyncConnection` and `AsyncCursor` classes, was introduced in version 2.2.1. Code attempting to use `await` with `sqlalchemy-jdbcapi` on older versions will fail or operate synchronously.
Install
-
pip install sqlalchemy-jdbcapi -
pip install sqlalchemy-jdbcapi[pyodbc]
Imports
- AsyncConnection
from sqlalchemy_jdbcapi.async_dbapi import AsyncConnection
- AsyncCursor
from sqlalchemy_jdbcapi.async_dbapi import AsyncCursor
Quickstart
import os
from sqlalchemy import create_engine, text
# Ensure JAVA_HOME is set for JPype to find a JVM
# Example: os.environ['JAVA_HOME'] = '/path/to/your/jdk'
# Example for PostgreSQL via JDBC
# Replace with your actual database details or environment variables
DB_USER = os.environ.get('JDBC_DB_USER', 'your_user')
DB_PASS = os.environ.get('JDBC_DB_PASS', 'your_password')
DB_HOST = os.environ.get('JDBC_DB_HOST', 'localhost')
DB_PORT = os.environ.get('JDBC_DB_PORT', '5432')
DB_NAME = os.environ.get('JDBC_DB_NAME', 'your_database')
# The dialect string uses 'jdbcapi+' followed by the driver name
# For PostgreSQL, it's 'postgresql'. For MySQL, 'mysql', etc.
jdbc_url = f"jdbcapi+postgresql://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
try:
engine = create_engine(jdbc_url)
with engine.connect() as connection:
result = connection.execute(text("SELECT 1"))
print(f"Connection successful, result: {result.scalar()}")
# Example with asyncio (requires sqlalchemy-jdbcapi>=2.2.1 and asyncpg, aiomysql, etc.)
# from sqlalchemy.ext.asyncio import create_async_engine
# async_jdbc_url = f"jdbcapi+postgresql+asyncpg://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
# async_engine = create_async_engine(async_jdbc_url)
# async def run_async_query():
# async with async_engine.connect() as conn:
# result = await conn.execute(text("SELECT 2"))
# print(f"Async connection successful, result: {result.scalar()}")
# import asyncio
# asyncio.run(run_async_query())
except Exception as e:
print(f"Error connecting to database: {e}")
finally:
# JPype requires explicit JVM shutdown in some contexts or when done
try:
from jpype import isJVMStarted, shutdownJVM
if isJVMStarted():
shutdownJVM()
print("JVM shut down.")
except ImportError:
pass # JPype might not be installed or available