当前位置:

首页 > 编程开发 > FastAPI连接Oracle数据库教程

FastAPI连接Oracle数据库教程

本教程详细阐述了如何使用FastAPI和SQLAlchemy连接并查询Oracle数据库中已存在的表。文章首先澄清了Base.metadata.create_all()在处理现有表时的默认行为,随后重点介绍了通过SQLAlchemy的反射机制,以声明式映射方式优雅地将Python模型与现有数据库表进行关联,并提供了完整的FastAPI接口示例,确保开发者能够高效、准确地操作现有数据库资产。

使用FastAPI与SQLAlchemy连接现有Oracle数据库表的教程

本教程详细阐述了如何使用FastAPI和SQLAlchemy连接并查询Oracle数据库中已存在的表。文章首先澄清了`Base.metadata.create_all()`在处理现有表时的默认行为,随后重点介绍了通过SQLAlchemy的反射机制,以声明式映射方式优雅地将Python模型与现有数据库表进行关联,并提供了完整的FastAPI接口示例,确保开发者能够高效、准确地操作现有数据库资产。

在现代Web应用开发中,特别是在构建微服务架构时,经常需要与已有的数据库进行交互。FastAPI因其高性能、易用性和自动文档生成能力,成为构建API的流行选择。而SQLAlchemy作为Python中最强大、最灵活的ORM(对象关系映射)工具之一,能有效管理数据库交互。本文将聚焦于一个常见但可能令人困惑的场景:如何使用FastAPI和SQLAlchemy连接并查询Oracle数据库中已存在的表,并解决开发者可能遇到的关于Base.metadata.create_all()的疑问。

理解 Base.metadata.create_all() 的默认行为

许多开发者在使用SQLAlchemy时,习惯于在定义模型后调用Base.metadata.create_all(bind=engine)来创建数据库表。然而,当数据库中表已存在时,会担心此操作是否会引发错误或重新创建表。

实际上,Base.metadata.create_all() 方法有一个关键参数 checkfirst,其默认值为 True。这意味着在尝试创建任何表之前,SQLAlchemy会首先检查该表是否已存在于数据库中。如果表已存在,它将跳过创建操作,从而避免了重复创建表可能导致的错误。因此,对于一个已存在的表,即使调用create_all,通常也不会导致问题。

以下是原始代码片段,它在处理现有表时并不会出错:

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
import cx_Oracle

from fastapi import Depends, FastAPI
from sqlalchemy import Column, Integer, String

# 初始化Oracle客户端 (路径需根据实际情况配置)
# cx_Oracle.init_oracle_client(lib_dir=r"E:\instantclient-basic-windows.x64-12.1.0.2.0\instantclient_12_1")

# 数据库连接字符串
my_database_connection = "oracle+cx_oracle://super:password@localhost:1521/db" # 请替换为您的实际连接信息

engine = create_engine(my_database_connection)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class table1(Base):
    __tablename__ = "table1"
    # 假设CN是主键,或者有唯一约束
    CN = Column(String(length=256), primary_key=True) # 假设CN是主键
    NAME = Column(String(length=40))
    EMAIL = Column(String(length=20))

# 即使table1已存在,此行也不会重新创建它,因为checkfirst=True是默认行为
Base.metadata.create_all(bind=engine) 

app = FastAPI()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/table_api/")
def read_users(db:Session = Depends(get_db)):
    cninformation = db.query(table1).all()
    return cninformation

尽管上述代码在功能上是正确的,但对于处理现有数据库表,SQLAlchemy提供了更明确和专业的“反射”机制。

声明式映射与现有表的反射机制

当数据库结构已由DBA管理或由其他系统生成时,我们通常不希望ORM去创建或修改表结构。此时,SQLAlchemy的反射机制允许我们“映射”到已存在的数据库表,而不是通过Python模型来定义它们。

以下是使用反射机制来连接和查询现有Oracle表的详细步骤及示例代码:

1. 初始化Oracle客户端与数据库连接

确保cx_Oracle库已安装,并且Oracle Instant Client已配置。cx_Oracle.init_oracle_client函数用于指定Instant Client的路径。

import cx_Oracle
# 请根据您的Oracle Instant Client实际安装路径进行配置
# cx_Oracle.init_oracle_client(lib_dir=r"E:\instantclient-basic-windows.x64-12.1.0.2.0\instantclient_12_1")

然后,配置数据库连接字符串并创建SQLAlchemy的引擎和会话工厂。

from sqlalchemy import create_engine, Column, String, Table, MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from fastapi import Depends, FastAPI

# 数据库连接配置
# 格式: oracle+cx_oracle://user:password@host:port/service_name
# 或者 oracle+cx_oracle://user:password@tnsname
my_database_connection = "oracle+cx_oracle://super:password@localhost:1521/db" # 替换为您的实际连接信息
engine = create_engine(my_database_connection)

# 创建数据库会话工厂
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# 创建声明式基类
Base = declarative_base()

# 创建MetaData对象,用于管理数据库元数据和反射表结构
metadata = MetaData() 

2. 定义反射模型

与直接声明模型不同,反射模型通过Table对象来映射现有表。我们使用Table('your_table_name', metadata, autoload_with=engine)来指示SQLAlchemy从数据库中加载指定表的结构。

class Table1(Base):
    __tablename__ = "table1" # 数据库中的实际表名

    # 关键:通过反射机制加载表结构
    # autoload_with=engine 会指示SQLAlchemy连接到数据库并加载'table1'的列信息
    __table__ = Table(__tablename__, metadata, autoload_with=engine) 

    # 如果需要,可以在这里定义额外的Python属性或方法
    # 例如,定义一个 __repr__ 方法方便调试
    def __repr__(self):
        # 假设CN是表中的一个列,通过反射获得
        return f""

说明:

  • __tablename__ 仍然用于指定数据库中的表名。
  • __table__ = Table(__tablename__, metadata, autoload_with=engine) 是反射的关键。它告诉SQLAlchemy,这个Python类Table1应该映射到数据库中名为table1的表,并且其列结构应该通过engine从数据库中自动加载。
  • 一旦__table__被反射,您就不需要在Python类中手动定义所有列(如CN = Column(...)),因为这些信息将自动从数据库中获取。

3. 构建FastAPI应用与查询接口

现在,我们可以将反射模型集成到FastAPI应用中,并定义API接口来查询数据。

app = FastAPI()

# 数据库会话依赖函数
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# 定义API接口
@app.get("/table_api/")
def read_table_data(db: Session = Depends(get_db)):
    """
    查询table1表的所有数据。
    """
    # 使用反射模型Table1进行查询
    data = db.query(Table1).all()
    return data

# 运行FastAPI应用
# 可以通过命令行运行:uvicorn your_script_name:app --reload
# 假设您的脚本名为 main.py,则运行:uvicorn main:app --reload

完整示例代码

将上述所有部分整合,形成一个完整的FastAPI应用,用于查询Oracle数据库中的现有表:

from sqlalchemy import create_engine, Table, MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
import cx_Oracle
from fastapi import Depends, FastAPI

# --- 1. 初始化Oracle客户端 (根据您的实际环境配置) ---
# cx_Oracle.init_oracle_client(lib_dir=r"E:\instantclient-basic-windows.x64-12.1.0.2.0\instantclient_12_1")

# --- 2. 数据库连接配置 ---
# 请替换为您的实际Oracle数据库连接信息
my_database_connection = "oracle+cx_oracle://super:password@localhost:1521/db" 
engine = create_engine(my_database_connection)

# 创建数据库会话工厂
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# 创建声明式基类和MetaData对象
Base = declarative_base()
metadata = MetaData() 

# --- 3. 定义反射模型 ---
class Table1(Base):
    __tablename__ = "table1" # 数据库中的实际表名
    # 通过反射机制加载表结构
    __table__ = Table(__tablename__, metadata, autoload_with=engine) 

    def __repr__(self):
        # 假设CN, NAME, EMAIL是表中的列,通过反射获得
        return f""

# --- 4. FastAPI应用初始化 ---
app = FastAPI()

# --- 5. 数据库会话依赖函数 ---
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# --- 6. 定义API接口 ---
@app.get("/table_api/")
def read_table_data(db: Session = Depends(get_db)):
    """
    查询table1表的所有数据。
    """
    data = db.query(Table1).all()
    return data

# --- 7. 运行FastAPI应用 (通过命令行) ---
# 将此代码保存为例如 main.py
# 在命令行中运行:uvicorn main:app --reload
# 然后访问 http://127.0.0.1:8000/table_api/ 查看结果

注意事项与最佳实践

  1. cx_Oracle客户端路径: 确保cx_Oracle.init_oracle_client中的lib_dir指向正确的Oracle Instant Client路径。在生产环境中,可能需要确保环境变量(如LD_LIBRARY_PATH或PATH)已正确配置,以便系统能找到Oracle客户端库。
  2. 数据库连接字符串安全: 数据库密码等敏感信息绝不应硬编码在代码中。应通过环境变量、配置文件(如.env文件配合python-dotenv)或密钥管理服务来安全地管理这些凭据。
  3. 模型命名规范: Python类名通常使用驼峰命名法(如Table1),而数据库表名通常是小写或下划线命名(如table1)。保持这种约定有助于代码的可读性。
  4. 反射的优势: 当数据库结构由DBA管理或可能频繁变更时,反射机制能让ORM模型自动适应这些变化,减少手动维护模型定义的开销,提高系统的健壮性。
  5. 错误处理: 在实际应用中,应添加更完善的错误处理机制,例如数据库连接失败、查询无结果、权限不足等情况,以提供友好的用户体验和更稳定的服务。
  6. 多表反射: 如果有多个表需要反射,可以为每个表创建相应的反射模型类,遵循相同的模式。
  7. 主键和索引: 虽然反射会自动加载列信息,但SQLAlchemy通常需要知道表的主键才能执行某些ORM操作(如按ID查询)。反射通常会正确识别主键。如果反射未正确识别,您可能需要在模型中显式指定。

总结

本文详细介绍了在FastAPI应用中,如何利用SQLAlchemy连接并查询Oracle数据库中已存在的表。我们首先澄清了Base.metadata.create_all()在处理现有表时的默认行为,即其checkfirst=True的默认设置会避免重复创建表。随后,我们重点讲解了通过声明式映射结合反射机制来优雅地处理现有数据库表,这种方式更符合操作现有数据库的专业实践。通过掌握这些方法,开发者可以避免重复定义已有的表结构,使代码更加健壮和易于维护,从而更高效地开发与现有数据库集成的FastAPI应用。

本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发
相关文章 更多
C++动态数组初始化怎么写?常用语句与代码示例
C++动态数组初始化怎么写?常用语句与代码示例

深入解析C++中动态数组的初始化机制,涵盖new操作符的不同用法、基本类型与类对象的初始化差异,以及为何在现代C++开发中应优先使用std::vector。

using namespace 使用中遇到的问题怎么解决
using namespace 使用中遇到的问题怎么解决

命名空间的基本概念与常见引入问题在C++等编程语言中,命名空间(namespace)是一种将代码标识符(如变量、函数、类名)封装在特定名称下的机制,其主要目的是避免命名冲突,尤其是在大型项目或使用多个第三方库时。使用“using namespace”指令可以将指定命名空间中的所有名称引入当前作用域,

c语言函数递归 实操经验总结:这些技巧很实用
c语言函数递归 实操经验总结:这些技巧很实用

理解递归的基本原理在C语言中,递归是一种函数调用自身的编程技术。要掌握它,首先需要理解其核心思想:将一个复杂的大问题,分解为一个或几个与原问题相似但规模更小的子问题,直到子问题足够简单,可以直接求解。这个过程通常包含两个关键部分:递归出口和递归体。递归出口定义了问题何时不再继续分解,即最简单、可直接

c语言函数递归 怎么选?常见方案对比分析
c语言函数递归 怎么选?常见方案对比分析

递归函数的基本概念与适用场景在C语言编程中,递归是一种函数调用自身的编程技巧。它并非适用于所有问题,但在处理某些具有自相似结构的问题时,能提供极其清晰和优雅的解决方案。递归的核心思想是将一个大规模问题分解为一个或多个同类型但规模更小的子问题,直到子问题简单到可以直接求解。典型的适用场景包括树形结构的

Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解
Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解

理解内存管理的基石在Objective-C的编程世界中,内存管理是开发者必须掌握的核心技能之一。它直接关系到应用的性能、稳定性与资源利用效率。与一些采用自动垃圾回收机制的语言不同,Objective-C在很长一段时间里,依赖一套基于引用计数的、需要开发者部分介入的管理规则。这套规则的核心思想是明确的

如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏
如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏

理解 dealloc 的角色与时机在 iOS 应用开发中,内存管理是保障应用性能与稳定性的基石。dealloc 方法是 Objective-C 中对象生命周期结束时的关键回调,它标志着对象即将被系统回收内存。正确理解其触发时机至关重要:当一个对象的引用计数降为零时,运行时系统会自动调用该对象的 de

深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制
深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制

内存管理的基石在Objective-C的世界里,内存管理是开发者必须掌握的核心技能之一。作为一门在手动引用计数(MRC)时代诞生的语言,Objective-C要求程序员对对象的生命周期有清晰的认识。dealloc方法正是这一生命周期中至关重要的终点站。它是一个实例方法,当对象的引用计数降为零时,系统

理解 native2ascii:Java 国际化开发中的字符编码工具
理解 native2ascii:Java 国际化开发中的字符编码工具

native2ascii 工具的基本定位在Ja va应用程序的国际化与本地化开发过程中,处理非拉丁字符集是一个常见且关键的环节。Ja va内部使用Unicode字符集来统一表示全球各种语言的文字,但其属性文件(.properties)在历史上要求使用ASCII编码,或者更准确地说,要求非ASCII字

如何使用 native2ascii 转换中文字符为 Unicode 转义序列
如何使用 native2ascii 转换中文字符为 Unicode 转义序列

理解 native2ascii 工具的基本用途在软件开发,特别是涉及国际化处理的场景中,开发者常常需要处理不同编码的文本资源。native2ascii 是 Ja va 开发工具包(JDK)中提供的一个命令行实用程序,其主要功能是将包含本地字符编码(非ASCII字符)的文件,转换为包含 Unicode

Java native2ascii 命令详解:解决属性文件乱码问题
Java native2ascii 命令详解:解决属性文件乱码问题

native2ascii 命令的由来与作用在Ja va开发中,处理国际化资源文件是一个常见需求。资源文件通常以.properties格式存储,用于支持多语言界面。然而,Ja va属性文件默认采用ISO-8859-1字符集编码,这导致了一个直接的问题:当文件中包含非拉丁字符(如中文、日文、韩文等)时,

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。