Python 如何使用sqlalchemy安全地进行并发更新?
我这里有一个玩具程序,它是用来混淆更新并添加到内存数据库中的。我的目的是将不同的项添加到数据库中,然后在单独的线程中更新每个项上的两个非主字段 然而,当在这个玩具程序中打印结果时,只有一个字段在要写入的第二个线程的末尾被更新。我的理解是Python 如何使用sqlalchemy安全地进行并发更新?,python,sqlalchemy,Python,Sqlalchemy,我这里有一个玩具程序,它是用来混淆更新并添加到内存数据库中的。我的目的是将不同的项添加到数据库中,然后在单独的线程中更新每个项上的两个非主字段 然而,当在这个玩具程序中打印结果时,只有一个字段在要写入的第二个线程的末尾被更新。我的理解是 session.query(User).populate_existing().with_for_update( read=False, nowait=False, of=User).fil
session.query(User).populate_existing().with_for_update(
read=False,
nowait=False,
of=User).filter_by(name=u.name).one()
应该从数据库中重新提取该项,然后在修改该项之前锁定该项的行。因此,更新项目的第二个线程应该将全名
和昵称
都设置为新的(尽管很愚蠢)值
我在这里做错了什么,而这从来没有发生过
程序代码:
import random, time
import multiprocessing
from sqlalchemy import create_engine, Column, Integer, String, UniqueConstraint
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
__table_args__ = (UniqueConstraint('nickname', 'fullname'),)
name = Column(String, primary_key=True)
fullname = Column(String)
nickname = Column(String)
def __repr__(self):
return "<User(name='%s', fullname='%s', nickname='%s')>" % (
self.name, self.fullname, self.nickname)
engine = create_engine('sqlite:///:memory:', echo=True)
Base.metadata.create_all(engine)
def database_change(count, id, out_list, engine):
"""
Creates an empty list and then appends a
random number to the list 'count' number
of times. A CPU-heavy operation!
"""
Session = sessionmaker(bind=engine)
session = Session()
name = ['CHEW', 'MARS BAR'][id]
for i in range(size):
time.sleep(random.random())
user = User(
name=f'cowface{i}',
fullname=f"biscuit{i}",
nickname=f'blah{i}')
print(i)
session.add(user)
print(f'thread {id}, number {i}')
session.commit()
for u in session.query(User).all():
print(u)
new_u = session.query(User).populate_existing().with_for_update(
read=False,
nowait=False,
of=User).filter_by(name=u.name).one()
print(f'thread {id} modifying')
if id == 0:
new_u.fullname = name
if id == 1:
new_u.nickname = name
session.commit()
print(session.query(User).all())
session.close()
if __name__ == "__main__":
size = 10 # Number of random items to add
procs = 2 # Number of processes to create
# Create a list of jobs and then iterate through
# the number of processes appending each process to
# the job list
jobs = []
for i in range(0, procs):
out_list = list()
process = multiprocessing.Process(target=database_change,
args=(size, i, out_list, engine))
jobs.append(process)
# Start the processes (i.e. calculate the random number lists)
for j in jobs:
j.start()
# Ensure all of the processes have finished
for j in jobs:
j.join()
print("operation complete.")
import random,time
导入多处理
从sqlalchemy导入创建引擎、列、整数、字符串、唯一约束
从sqlalchemy.ext.declarative导入声明性基础
从sqlalchemy.orm导入sessionmaker
Base=声明性_Base()
类用户(基本):
__tablename_uu='users'
__表参数(UniqueConstraint('昵称','fullname'),)
名称=列(字符串,主键=True)
fullname=列(字符串)
昵称=列(字符串)
定义报告(自我):
返回“”%(
self.name、self.fullname、self.昵称)
engine=create_engine('sqlite://:memory:',echo=True)
Base.metadata.create_all(引擎)
def数据库更改(计数、id、输出列表、引擎):
"""
创建一个空列表,然后附加一个
随机数到列表“计数”数
好几次。一个CPU繁重的操作!
"""
会话=会话生成器(绑定=引擎)
会话=会话()
name=['CHEW','MARS BAR'][id]
对于范围内的i(尺寸):
time.sleep(random.random())
用户=用户(
name=f'cowface{i}',
全名=f“饼干{i}”,
昵称=f'blah{i}')
印刷品(一)
session.add(用户)
打印(f'thread{id},number{i})
session.commit()
对于会话中的u.query(用户).all():
打印(u)
new\u=session.query(用户)。使用用于更新的\u填充\u existing()(
read=False,
nowait=False,
of=User).filter_by(name=u.name).one()
打印(f'thread{id}修改')
如果id==0:
new_.fullname=名称
如果id==1:
新昵称=名称
session.commit()
打印(session.query(User.all())
session.close()
如果名称=“\uuuuu main\uuuuuuuu”:
大小=10#要添加的随机项目数
procs=2#要创建的进程数
#创建作业列表,然后遍历
#将每个进程附加到的进程数
#工作清单
工作=[]
对于范围内的i(0,进程):
out_list=list()
进程=多进程。进程(目标=数据库更改,
args=(大小、i、输出列表、引擎))
jobs.append(进程)
#启动流程(即计算随机数列表)
对于工作中的j:
j、 开始()
#确保所有流程都已完成
对于工作中的j:
j、 加入
打印(“操作完成”)