How can I, using sqlalchemy, do something like this?
user = session.query("select * from user")
if user.state == "active"
session.query("update user set state = 'inactive' where id = %d" % user.id)
I need the select and update to be one atomic operation. Another program should not be able to select/update the user while the operation is going.
How can I do it concurrently?
Note: I need to know if we succeeded in change the state or not.
How can I achieve that?
Am I doing it wrong?
Should it be a stored procedure?
Should I use database "lock"?
These are mainly of use in atomic data structures in which several volatile fields of the same node (for example, the links of a tree node) are independently subject to atomic updates.
All three methods (plus computeIfPresent) are guaranteed to be atomic in ConcurrentHashMap. The way that works is that the method synchronizes on the new or existing Entry in the HashTable whilst executing.
AtomicReferenceFieldUpdater , AtomicIntegerFieldUpdater, and AtomicLongFieldUpdater are reflection-based utilities that provide access to the associated field types.
Package java.util.concurrent.atomic A small toolkit of classes that support lock-free thread-safe programming on single variables. Instances of Atomic classes maintain values that are accessed and updated using methods
You can do this by setting an isolation level of Serializable, which can be done on a specific session with SQLAlchemy using session.connection(execution_options={'isolation_level': 'SERIALIZABLE'})
. If two connections conflict (they both read before the other wrote), committing the transaction will fail, and you can just loop until it goes through.
from sqlalchemy import Column, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.types import Boolean, Integer, String
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
active = Column(Boolean, nullable=False)
url = 'postgresql://postgres@localhost/test'
engine = create_engine(url, echo=True)
if not engine.dialect.has_table(engine.connect(), 'users'):
Base.metadata.create_all(bind=engine)
Session = sessionmaker(bind=engine)
session = Session()
session.add(User(name="remram", active=True))
session.commit()
Session = sessionmaker(bind=engine)
session = Session()
session.connection(execution_options={'isolation_level': 'SERIALIZABLE'}) # Commenting this line will make this unsafe in a concurrent environment
user = session.query(User).filter(User.name == "remram").one()
if user.active:
user.active = False
raw_input() # So you can run this twice
session.commit()
If your database supports SELECT FOR UPDATE (ie: PostgreSQL) you could use:
user = session.query("select * from user where id = %d for update" % theId)
if user.state == "active"
session.query("update user set state = 'inactive' where id = %d" % user.id)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With