sqlalchemy-多线程、多并发下修改数据库数据


sqlalchemy中多线程下,读取数据库信息同时修改数据库信息可能会出现幻读。

创建数据库

from flask_sqlalchemy import SQLAlchemy
from flask import Flask

app = Flask(__name__)

app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:root@localhost:3306/test"  # 数据库要先创建
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SECRET_KEY"] = "DsdfFHERsdadad234+J"

db = SQLAlchemy(app)


class Stu(db.Model):
    __tablename__ = "student"  # 自动生成表,表名为student
    id = db.Column(db.Integer, primary_key=True)  # 创建一个整数型的主键
    name = db.Column(db.String(20), nullable=False)
    select_num = db.Column(db.Integer, nullable=False)
if __name__ == '__main__':
    db.create_all()

 创建一个案例

from model import Stu,db

stu = Stu()
stu.name = "张三"
stu.select_num = 0
db.session.add(stu)
db.session.commit()
from model import Stu, db
from threading import Thread


def add_execute_times():
    student = Stu.query.filter(Stu.id == 1).one()
    student.select_num += 1
    print(student.select_num)
    stu = Stu.query.filter(Stu.id == 1).update({"select_num": student.select_num})
    db.session.commit()


thread_list = []
for i in range(10):
    t = Thread(target=add_execute_times)
    thread_list.append(t)
for i in thread_list:
    i.start()
for i in thread_list:
    i.join()
输出结果:

1
11

 
 

1
1
1
11
1

 
 

2

 

为了保证读取数据的原子性,可以采用锁来控制数据库的读取。

在sqlalchemy中,with_for_update(self, read=False, nowait=False, of=None)语句可以为数据库添加锁。

  • read:是标识加互斥锁还是共享锁. 当为 True 时, 即 for share 的语句, 是共享锁. 多个事务可以获取共享锁, 互斥锁只能一个事务获取. 有"多个地方"都希望是"这段时间我获取的数据不能被修改, 我也不会改", 那么只能使用共享锁.
  • nowait:其它事务碰到锁, 是否不等待直接"报错".
  • of:指明上锁的表, 如果不指明, 则查询中涉及的所有表(行)都会加锁.
from model import Stu, db
from threading import Thread


def add_execute_times():
student = Stu.query.with_for_update(read=False, nowait=False).filter(Stu.id == 1).one()
  #添加锁with_for_update,锁会在commit时打开
student.select_num += 1
print(student.select_num)
stu = Stu.query.filter(Stu.id == 1).update({"select_num": student.select_num})
db.session.commit()


thread_list = []
for i in range(10):
t = Thread(target=add_execute_times)
thread_list.append(t)
for i in thread_list:
i.start()
for i in thread_list:
i.join()
输出结果:

1
2
3
4
5
6
7
8
9
10

 
  
 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM