gpt4 book ai didi

python - 在 Google Cloud SQL (GAE) Python 应用程序中管理数据库连接的好方法是什么?

转载 作者:IT王子 更新时间:2023-10-29 00:32:10 26 4
gpt4 key购买 nike

我刚刚开始学习 Google App Engine,并且正在尝试找出一种好的方法来管理我的数据库与 Google Cloud SQL 实例的连接(如果您还没有使用过 GC-SQL,基本上,它是云中的 MySQL,有一些限制)。

我使用 python (2.7) GAE 环境和 webapp2 框架来处理请求。我知道常见问题解答说建议对每个请求建立一个到数据库的新连接,但我不知道关闭连接的推荐方法是什么。每次我在开发过程中尝试删除表时,GC-SQL 都会挂起并且“show processlist”显示有一堆进程(可能是因为我没有关闭数据库)并且其中一个正在等待锁(可能是试图删除表的过程)。这很烦人,迫使我重新启动 GC-SQL 实例(就像重新启动 mysql-server 服务一样,我想)。偶尔也会出现数据库问题,我认为这与我没有真正关闭数据库连接这一事实有关。

因此,例如,我是否应该在我的 webapp2.Requesthandler 子类实例上有一个析构函数来断开与数据库的连接? GAE 对象有时似乎被缓存,所以这也是需要考虑的事情。我想我可以为每个查询连接/查询/断开连接,但这似乎不是最佳选择。

我知道这是一个模糊的问题,但我希望在这方面玩过的人能给我一些提示。

提前致谢!

更新:我尝试使用 Shay 的回答作为起点,围绕需要游标的方法实现包装器。我收到 GAE 错误。这是一个特定于此的新问题:What are the connection limits for Google Cloud SQL from App Engine, and how to best reuse DB connections?

最佳答案

这是来自 Getting Started Guide 的 helloworld 示例应用程序的完整示例.它基于来自 Shay Erlichmen 的片段和 JJC ,但这个版本是线程安全的。

你可以这样使用它:

  @with_db_cursor(do_commit = True)
def get(self, cursor):
cursor.execute('SELECT guestName, content, entryID FROM entries')

app.yaml

application: helloworld
version: 1
runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /.*
script: helloworld.app

helloworld.py

import cgi
import logging
import os
import threading
import webapp2

from google.appengine.api import rdbms

_INSTANCE_NAME = <name goes here>

def _db_connect():
return rdbms.connect(instance=_INSTANCE_NAME, database='guestbook')

_mydata = threading.local()

def with_db_cursor(do_commit = False):
""" Decorator for managing DB connection by wrapping around web calls.

Stores connections and open cursor count in a threadlocal
between calls. Sets a cursor variable in the wrapped function. Optionally
does a commit. Closes the cursor when wrapped method returns, and closes
the DB connection if there are no outstanding cursors.

If the wrapped method has a keyword argument 'existing_cursor', whose value
is non-False, this wrapper is bypassed, as it is assumed another cursor is
already in force because of an alternate call stack.
"""
def method_wrap(method):
def wrap(self, *args, **kwargs):
if kwargs.get('existing_cursor', False):
# Bypass everything if method called with existing open cursor.
return method(self, None, *args, **kwargs)

if not hasattr(_mydata, 'conn') or not _mydata.conn:
_mydata.conn = _db_connect()
_mydata.ref = 0
_mydata.commit = False

conn = _mydata.conn
_mydata.ref = _mydata.ref + 1

try:
cursor = conn.cursor()
try:
result = method(self, cursor, *args, **kwargs)
if do_commit or _mydata.commit:
_mydata.commit = False
conn.commit()
return result
finally:
cursor.close()
finally:
_mydata.ref = _mydata.ref - 1
if _mydata.ref == 0:
_mydata.conn = None
logging.info('Closing conn')
conn.close()
return wrap
return method_wrap


class MainPage(webapp2.RequestHandler):
@with_db_cursor(do_commit = True)
def get(self, cursor):
cursor.execute('SELECT guestName, content, entryID FROM entries')
self.response.out.write("""
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>My Guestbook!</title>
</head>
<body>""")
self.response.out.write("""
<table style="border: 1px solid black">
<tbody>
<tr>
<th width="35%" style="background-color: #CCFFCC; margin: 5px">Name</th>
<th style="background-color: #CCFFCC; margin: 5px">Message</th>
<th style="background-color: #CCFFCC; margin: 5px">ID</th>
</tr>""")
for row in cursor.fetchall():
self.response.out.write('<tr><td>')
self.response.out.write(cgi.escape(row[0]))
self.response.out.write('</td><td>')
self.response.out.write(cgi.escape(row[1]))
self.response.out.write('</td><td>')
self.response.out.write(row[2])
self.response.out.write('</td></tr>')

self.response.out.write("""
</tbody>
</table>
<br /> No more messages!
<br /><strong>Sign the guestbook!</strong>
<form action="/sign" method="post">
<div>First Name: <input type="text" name="fname" style="border: 1px solid black"></div>
<div>Message: <br /><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
</body>
</html>""")

class Guestbook(webapp2.RequestHandler):
@with_db_cursor(do_commit = True)
def post(self, cursor):
fname = self.request.get('fname')
content = self.request.get('content')
# Note that the only format string supported is %s
cursor.execute('INSERT INTO entries (guestName, content) VALUES (%s, %s)', (fname, content))

self.redirect("/")

app = webapp2.WSGIApplication(
[('/', MainPage),
('/sign', Guestbook)],
debug=True)

关于python - 在 Google Cloud SQL (GAE) Python 应用程序中管理数据库连接的好方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10158805/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com