[PYTHON] Pièges de SQL Alchemy

introduction

SQLAlchemy est un mappeur OR qui est souvent utilisé lors de l'accès à une base de données avec python. Utilisation de sqlalchemy pour accéder à la base de données avec python résume des choses autres que SQL. Cette fois, j'ai résumé les choses qui peuvent poser problème si vous ne comprenez pas SQL Alchemy.

environnement

Ce que vous pouvez obtenir avec SQL et SQL Alchemy est différent

Vous pouvez utiliser des instructions SQL directement dans SQLAlchemy en plus de la mise à jour avec ORM. Veuillez noter que les informations souhaitées ne peuvent être obtenues si la méthode de mise à jour à partir de la base de données et la méthode d'acquisition de celle-ci sont différentes.

Exemple concret

Même dans la même session, si vous essayez d'obtenir le contenu modifié par l'instruction SQL avant de valider avec ORM, celle avant la mise à jour sera prise. L'inverse est également vrai.

Expérience

Après la mise à jour avec l'instruction SQL ou ORM, obtenez-le avec l'instruction SQL et ORM et affichez le contenu.

Source expérimentale

Si vous configurez une nouvelle session, vous irez chercher les informations de la base de données, de sorte que la fonction de mise à jour et la fonction d'affichage ont la même session. En outre, étant donné que la variable de mise à jour ne souhaite pas affecter la variable d'affichage, la mise à jour et l'affichage sont créés en tant que fonctions distinctes. Veuillez consulter Précédent pour créer une session.

main.py



def get_mapper_and_query(local_session):
    print('============== query get ===============')
    records = local_session.execute("select * from pets where id = 3;")
    for record in records:
        print(record)
    print('============== mapper get ===============')
    pet2 = local_session.query(Pets).filter(Pets.id==3).first()
    print(pet2)
 
def update_mapper_and_query():
    local_session = SESSION()
    print('*************************** default ***************************')
    get_mapper_and_query(local_session)
    print('*************************** default ***************************\n')

    print('*************************** mapper update ***************************')
    pet = local_session.query(Pets).filter(Pets.id==3).first()
    pet.age = 10
    get_mapper_and_query(local_session)
    print('*************************** mapper update ***************************')

    print('*************************** query update ***************************')
    local_session.execute("update pets set age=20 where id = 3;")
    get_mapper_and_query(local_session)
    print('*************************** query update ***************************\n')

résultat

À l'origine, l'âge était de 5 ans, mais il n'est mis à jour à 10 que lorsqu'il est acquis par ORM après la mise à jour de l'ORM. En outre, après la mise à jour de l'instruction SQL, l'âge est mis à jour à 20 lorsque l'instruction SQL est acquise, et 10 lorsque l'ORM est mis à jour reste tel qu'il est lorsque l'ORM est acquis. De cette façon, si chaque méthode de mise à jour et méthode d'acquisition sont différentes, ce que vous pouvez obtenir sera différent.


*************************** default ***************************
============== query get ===============
(3, 'mink', 5, datetime.datetime(1990, 2, 12, 0, 0))
============== mapper get ===============
id:3, name:mink, age:5, birthday:1990-02-12 00:00:00
*************************** default ***************************

*************************** mapper update ***************************
============== query get ===============
(3, 'mink', 5, datetime.datetime(1990, 2, 12, 0, 0))
============== mapper get ===============
id:3, name:mink, age:10, birthday:1990-02-12 00:00:00
*************************** mapper update ***************************
*************************** query update ***************************
============== query get ===============
(3, 'mink', 20, datetime.datetime(1990, 2, 12, 0, 0))
============== mapper get ===============
id:3, name:mink, age:10, birthday:1990-02-12 00:00:00
*************************** query update ***************************

Le nombre de connexions au DB augmentera

SQLAlchemy a une fonction de pool de connexions. Si vous souhaitez que le programme continue de fonctionner en permanence, le nombre de connexions augmentera régulièrement à moins que vous ne compreniez quand les connexions sont créées.

Exemple concret

Lorsque j'ai créé un service WEB pour obtenir des informations DB avec flask, j'ai atteint la limite supérieure du nombre de sessions DB et j'ai commencé à faire une erreur.

Expérience

Créez un service qui acquiert des informations de la base de données avec flask et vérifiez le nombre de connexions côté base de données.

Source expérimentale

Il s'agit d'une source qui crée une session dans la base de données et renvoie des informations lorsqu'une demande est reçue. Cette fois, le nom d'application py_app est donné à la session de base de données pour une meilleure compréhension. Pour la connexion à la base de données, Accéder à la base de données avec python à l'aide de sqlalchemy, pour flask, [Comment renvoyer l'état http avec flask](https: / Voir /qiita.com/mink0212/items/52e0ebd66bd94e1303c1).

main.py



from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from flask import Flask, jsonify
from Pets import Pets

DATABASE = 'postgresql'
USER = 'postgres'
PASSWORD = 'postgres'
HOST = 'localhost'
PORT = '5431'
DB_NAME = 'animal_db'


CONNECT_STR = '{}://{}:{}@{}:{}/{}'.format(
    DATABASE,
    USER,
    PASSWORD,
    HOST,
    PORT,
    DB_NAME
)

app = Flask(__name__)


@app.route('/hello/<name>')
def hello(name):
    engine = create_engine(CONNECT_STR, connect_args={"application_name":"py_app"})
    session = sessionmaker(engine)()
    pets = session.query(Pets).filter(Pets.name==name).all()
    return jsonify(pets)

if __name__ == "__main__":
    app.run()

résultat

Nombre de sessions au démarrage


postgres=# select count(*) from pg_stat_activity where application_name = 'py_app';
 count
-------
     0
(1 row)

Nombre de sessions après la première demande


postgres=# select count(*) from pg_stat_activity where application_name = 'py_app';
 count
-------
     1
(1 row)

Nombre de sessions après la deuxième demande


postgres=# select count(*) from pg_stat_activity where application_name = 'py_app';
 count 
-------
     2
(1 row)

Nombre de séances après la 30e demande


postgres=# select count(*) from pg_stat_activity where application_name = 'py_app';
 count
-------
    30
(1 row)

Comme vous pouvez le voir, chaque fois que vous émettez une demande, une session est mise en place. Pour éviter cela, vous devez déplacer la session ou fermer la session et supprimer le moteur avant la réponse.

en conclusion

La différence de valeur obtenue cette fois-ci peut être trouvée dans le test, mais si la session n'est pas bonne, elle peut ne pas être trouvée et c'est très dangereux. Certaines personnes utilisent ORM sans le comprendre pleinement car il est pratique à utiliser, mais il est nécessaire de le comprendre pleinement car il peut être accro à de tels pièges.

Recommended Posts

Pièges de SQL Alchemy
sqlalchemy
didacticiel sqlalchemy
Mémo SQLAlchemy
SQLAlchemy BaseModel
[SQL Alchemy] Lire les données