Reputation: 809
I have created a flask app with mysql as backend. To initiate DB connection, I have used the following:
@app.before_request
def db_connect():
try:
g.db = MySQLdb.connect(host="localhost", user="root", passwd="", db="ddb",cursorclass=MySQLdb.cursors.DictCursor,autocommit=True)
except Exception as e:
print(e)
@app.teardown_request
def db_disconnect(exception=None):
try:
if g.db is not None:
g.db.close()
except Exception as e:
print(e)
Load this in the init_py. But I have checked how many time this mysql is opening and close, Its lot. Because the connection is open and close, even if a css/js file request calls. I calls the g.db in all functions. How do avoid this?
Upvotes: 1
Views: 1587
Reputation: 5119
Good question. Basically, the code you provided starts a db connection before each request. Each visited url is one request - including retrieved images or stylesheets -, so that's quite often.
What to do?
This snippet might be a bit more efficient, but will still create a database at each request. You could check it out.
Its advisable to route directly to your statics. That will remove a lot of request when the database connection for sure is not required. There are some options to do this with flask itself - see this post. I personally use flask + WSGI
, and add this little script above the line WSGIDaemonProcess
in my httpd.conf
file.
Alias "/static/" "/home/user/webapps/flask_app/flask_app/static/"
<Directory "/home/user/webapps/flask_app/flask_app/static/">
Require all granted
</Directory>
Do all your views need the db? Otherwise only get the connection on the required views.
from functools import wraps
from flask import g
def make_db_connection(func):
""" decorate views that need a database connection """
@wraps(func)
def decorated_function(*args, **kwargs):
if 'db' not in g:
g.db = connect_to_database()
return func(*args, **kwargs)
return decorated_function
@app.teardown_appcontext
def teardown_db():
""" close if opened """
db = g.pop('db', None)
if db is not None:
db.close()
You can make a small class
/ API
around your database and cache the most common request. Only works for select
of course. See this pretty project.
class Database():
@threaded_cached_property_with_ttl(ttl=60*60) # in seconds
def some_popular_query():
connection = MySQLdb.connect(host="localhost", user="", passwd="", db="")
return connection.get_query()
Illustration
To illustrate, Let's say we have a simple website with template/main.html
.
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"</script>
<script src="static/style/test.css"></script>
</head>
<body>
{{message}}
<img src="static/img/test.png' />
</body>
And index.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return render_template('index.html', message='Hello world')
With the flask site you describe, you will have one request for the page and template, another request for the stylesheet and another one for the images. That's 3 calls to your database!
Upvotes: 2