跨会话序列化数据库连接

时间:2012-06-07 17:22:08

标签: python oracle flask cx-oracle

我正在开发一个需要使用最终用户提供的凭据登录数据库的Web应用程序;应用程序本身没有登录数据库。

问题是如何为每个用户会话创建一个连接

一种方法是:

  1. 申请用户凭据
  2. 检查凭据对db后端是否有效
  3. 将凭据存储在会话级变量
  4. 此方法的问题是,在该会话的每个后续请求中;你需要创建一个新的连接;这将很快耗尽与服务器的最大连接。

    我在Oracle中使用Flask

    在Flask中,有一个g对象,用于存储请求范围的对象。但是这个片段不起作用:

    app = Flask(__name__)
    app.config.from_object(__name__)
    
    def login_required(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            if g.db is None:
                return redirect(url_for('login', next=request.url))
            return f(*args, **kwargs)
         return decorated_function
    
    class LoginForm(Form):
        username = TextField('Username', [validators.Length(min=4, max=25)])
        password = PasswordField('Password', [validators.Required()])
    
    @app.route('/app', methods=['GET','POST'])
    @login_required
    def index():
        return 'Index'
    
    @app.route('/', methods=['GET','POST'])
    def login():
        form = LoginForm(request.form)
        if request.method == 'POST':
            if form.validate():
               try:
                   dsn = cx_Oracle.makedsn(app.config['DB_HOST'],
                                           app.config['DB_PORT'], app.config['DB_SID'])
                   g.db = cx_Oracle.connect(form.username.data,
                                            form.password.data, dsn)
               except cx_Oracle.DatabaseError as e:
                   flash(unicode(e), 'error')
                   return render_template('login.html', form=form)
                return redirect(url_for('index'))
            else:
                return render_template('login.html', form=form)
        else:
            return render_template('login.html', form=form)
    

    AttributeError: '_RequestGlobals' object has no attribute 'db'

2 个答案:

答案 0 :(得分:1)

此代码段不起作用的原因是此行

    if g.db is None:

您正在访问不属于g的属性。添加以下代码行:

    @app.before_request
    def before_request():
         g.db = None

在请求之前调用以before_request()标记的函数,并且不传递任何参数。

关于连接池

Python中有一个名为SQLAlchemy的ORM和SQL工具包,它会自动为您执行连接池。 它还管理了烧瓶的g对象,并创建了更加安全的准备好的SQL语句。

它有两部分:

    1. Core which is a SQL abstraction toolkit.
    2. ORM is an optional package which builds on top of Core.

因此,如果您不想使用ORM,那么只需使用其Core并保持所有功能。 检查here

它通过cx_Oracle支持Oracle,可以按照SQLAlchemy Docs here中的说明进行设置。

检查此question以获取有关python中连接池的更多讨论。

答案 1 :(得分:0)

听起来你需要实现连接池。您只需使用所需属性检查池中的连接,而不是为每个请求(根本不进行扩展)请求新连接。如果没有合适的连接可用,则池将创建一个新连接。当然,在关闭一段时间未使用的连接时,池也需要处理相反的情况。

您可能想要检查这样的池是否可用于python。对于java,oracle支持使用UCP和OCI使用会话池。如果我没有弄错,甚至会为.Net提供连接池。