Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does SQLAlchemy track database changes?

I wonder how SQLAlchemy tracks changes that are made outside of SQLAlchemy (manual change for example)?

Until now, I used to put db.session.commit() before each value that can be changed outside of SQLAlchemy. Is this a bad practice? If yes, is there a better way to make sure I'll have the latest value? I've actually created a small script below to check that and apparently, SQLAlchemy can detect external changes without db.session.commit() being called each time.

Thanks,

P.S: I really want to understand how all the magics happen behind SQLAlchemy work. Does anyone has a pointer to some docs explaining the behind-the-scenes work of SQLAlchemy?

import os

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# Use SQLlite so this example can be run anywhere.
# On Mysql, the same behaviour is observed
basedir = os.path.abspath(os.path.dirname(__file__))
db_path = os.path.join(basedir, "app.db")
app.config["SQLALCHEMY_DATABASE_URI"] = 'sqlite:///' + db_path
db = SQLAlchemy(app)


# A small class to use in the test
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))


# Create all the tables and a fake data
db.create_all()
user = User(name="old name")
db.session.add(user)
db.session.commit()


@app.route('/')
def index():
    """The scenario: the first request returns "old name" as expected.
    Then, I modify the name of User:1 to "new name" directly on the database.
    On the next request, "new name" will be returned.
    My question is: how SQLAlchemy knows that the value has been changed?
    """

    # Before, I always use db.session.commit() 
    # to make sure that the latest value is fetched.
    # Without db.session.commit(), 
    # SQLAlchemy still can track change made on User.name
    # print "refresh db"
    # db.session.commit()

    u = User.query.filter_by(id=1).first()
    return u.name


app.run(debug=True)
like image 691
Son Avatar asked Nov 18 '15 17:11

Son


People also ask

How does SQLAlchemy update data?

Update table elements in SQLAlchemy. Get the books to table from the Metadata object initialized while connecting to the database. Pass the update query to the execute() function and get all the results using fetchall() function. Use a for loop to iterate through the results.

What Does MetaData do in SQLAlchemy?

The database usually consists of Tables and Columns. The Database Metadata serves us in generating SQL queries and Object Relational Mapping. It helps us in generating a Schema. The most fundamental objects of Database MetaData are MetaData, Table, and Column.

Does SQLAlchemy cache query?

Caching the query object so that Python interpreter doesn't have to manually re-assemble the query string every time. These queries are called baked queries and the cache is called baked . Basically it caches all the actions sqlalchemy takes BEFORE hitting the database--it does not cut down on database calls.


1 Answers

The "cache" of a session is a dict in its identity_map (session.identity_map.dict) that only caches objects for the time of "a single business transaction" , as answered here https://stackoverflow.com/a/5869795.

For different server requests, you have different identity_map. It is not a shared object.

In your scenario, you requested the server 2 separated times. The second time, the identity_map is a new one (you can easily check it by printing out its pointer), and has nothing in cache. Consequently the session will request the database and get you the updated answer. It does not "track change" as you might think.

So, to your question, you don't need to do session.commit() before a query if you have not done a query for the same object in the same server request.

Hope it helps.

like image 116
Nhat Cuong Nguyen Avatar answered Oct 02 '22 23:10

Nhat Cuong Nguyen