简体   繁体   中英

Is it a good practice to pass db connection as parameter to methods?

I am writing Python application to operate on Postgres database with SQLAlchemy. Specified the database information in a settings.py

DATABASE = {
    'drivername': 'postgres',
    'host': 'xyz.com',
    'port': '5432',
    'username': 'user',
    'password': 'pass',
    'database': 'db_dev'
}

Then I created a db_connection.py with a method to create a connection.

from sqlalchemy import *
from sqlalchemy.engine.url import URL

from . import settings

def get_engine():
    return create_engine(URL(**settings.DATABASE))

I want to have another module db_ops.py that has all the database operation func1 , func2 methods and call them in the main application module

engine = db.connection.get_engine()
db_ops.func1()
db_ops.func2()

And that means I will need to pass engine as a parameter to these methods.

func1(engine)
func2(engine)

Somehow I don't like the idea of making db connection as method parameter. Is there a better way to do it?

An Engine is not a connection. You can think of it as a connection pool. Usually the most natural way to to use an engine is to put it at the global level. In your case, you can put it in db_connection.py :

from sqlalchemy import *
from sqlalchemy.engine.url import URL

from . import settings

engine = create_engine(URL(**settings.DATABASE))

Then, you can import it in your db_ops module:

from db_connection import engine

def func1():
    engine.execute(...)

However, for a series of related queries you probably want to execute them in a single transaction, which necessitates passing around the actual connection:

with engine.begin() as connection:
    func1(connection)
    func2(connection)

To solve this problem, we have the concept of a scoped_session (again, also at the global level):

engine = create_engine(URL(**settings.DATABASE))
Session = scoped_session(sessionmaker(bind=engine))

Each time Session is called, it checks to see if there's already a session for the current thread, and creates it if it doesn't, obviating the need to pass around the connection:

from db_connection import Session

def func1():
    Session.execute(...)

In the caller of db_ops functions:

try:
    func1()
    func2()
    Session.commit()
finally:
    Session.remove()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM