Python中如何在Flask项目中使用SQLAlchemy实现Oracle多用户访问?

一般对于一个 orm 框架的项目来说,模型代码

class User(db.Model):
    __tablename__ = 'user'
    id = Column(BigInteger, primary_key=True)
    a = Column(String)

最终程序会发给数据库 SQL 代码

SELECT user.id AS user_id, user.a AS user_a 
FROM user

但是在 oracle 中,user 表前面存在一个数据库的用户概念(比如说 user1 ),所以,必须发送如下代码才能获取数据

SELECT user.id AS user_id, user.a AS user_a 
FROM user1.user

但是实际上,按照

https://www.oschina.net/question/237257_37964 提供的方案,模型更改为

class User(db.Model):
    __tablename__ = 'user1.user'
    __table_args__ = {'quote': False}
    id = Column(BigInteger, primary_key=True)
    a = Column(String)

实际上程序给数据库发送的 SQL 代码是

SELECT user1.user.id AS user1.user_id, user1.user.a AS user1.user_a 
FROM user1.user

这样的代码是获取不到数据的

还需要什么东西才能让程序发送正确的代码?

SELECT user.id AS user_id, user.a AS user_a 
FROM user1.user

Python中如何在Flask项目中使用SQLAlchemy实现Oracle多用户访问?

4 回复

在Flask项目里用SQLAlchemy搞Oracle多用户访问,关键得动态创建引擎和会话。直接用scoped_session配合线程局部变量来管理不同用户的数据库连接。下面是个完整示例:

from flask import Flask, g, request
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
import threading

app = Flask(__name__)

# 用户连接信息存储(实际项目用更安全的方式)
user_connections = {}

def get_user_engine(username, password):
    """为每个用户创建独立的引擎"""
    if (username, password) not in user_connections:
        # Oracle连接字符串格式
        dsn = f'oracle+cx_oracle://{username}:{password}@hostname:1521/service_name'
        engine = create_engine(dsn, echo=True)
        user_connections[(username, password)] = engine
    return user_connections[(username, password)]

# 创建线程局部的session工厂
Session = scoped_session(sessionmaker(), scopefunc=lambda: threading.current_thread().ident)

@app.before_request
def setup_user_session():
    """每个请求前设置用户特定的session"""
    # 从请求中获取用户凭证(实际项目应从认证中间件获取)
    username = request.headers.get('X-Username')
    password = request.headers.get('X-Password')
    
    if username and password:
        user_engine = get_user_engine(username, password)
        # 绑定session到用户特定的engine
        Session.configure(bind=user_engine)
        g.db_session = Session
    else:
        # 默认连接或错误处理
        pass

@app.teardown_appcontext
def shutdown_session(exception=None):
    """请求结束后清理session"""
    if hasattr(g, 'db_session'):
        g.db_session.remove()

@app.route('/query')
def query_data():
    """使用当前用户的session查询数据"""
    session = g.db_session
    # 执行查询操作
    # result = session.query(User).all()
    return "Query executed with user-specific connection"

if __name__ == '__main__':
    app.run(debug=True)

核心思路就是根据不同的用户凭证创建独立的Engine实例,然后用scoped_session确保每个线程(请求)使用正确的session。注意实际项目中用户凭证应该从安全的认证系统获取,而不是像示例中从请求头直接读取。

用scoped_session管理多用户会话。

我瞧了一下感觉和我想要的差距蛮大

这个问题已解决,写配置文件的时候把 user1 加入到 url 中,即
"url": “oracle+cx_oracle://user1:user1@XXXX:1521/XX”

回到顶部