您的位置:首页 > 数据库

数据库连接池SQLAlchemy中多线程安全的问题

2018-03-08 16:29 417 查看

1、数据库模块model.py

from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
session_factory = sessionmaker(bind=some_engine)
Session = scoped_session(session_factory)


2、业务模块thread.py

import threading
from model import Session

class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(20))
fullname = Column(String(20))
password = Column(String(20))
age = Column(Integer)

class MyThread(threading.Thread):

def __init__(self, threadName):
super(MyThread, self).__init__()
self.name = threading.current_thread().name

def run(self):
session = Session() #每个线程都可以直接使用数据库模块定义的Session
session.query(User).all()
user = User(name="hawk-%s"%self.name, fullname="xxxx",password="xxxx",age=10)
session.add(user)
time.sleep(1)
if self.name == "thread-9":
session.commit()
Session.remove()

if __name__ == "__main__":
arr = []
for i in xrange(10):
arr.append(MyThread('thread-%s' % i))
for i in arr:
i.start()
for i in arr:
i.join()


错误示范:

class MyThread(threading.Thread):

def __init__(self, threadName):
super(MyThread, self).__init__()
self.session = Session() #错误!
self.name = threading.current_thread().name

def run(self):
self.session.query(User).all()
user = User(name="hawk-%s"%self.name, fullname="xxxx",password="xxxx",age=10)
self.session.add(user)
time.sleep(1)
if self.name == "thread-9":
self.session.commit()
Session.remove()


错误解析:

看了SQLAlchemy之后源码发现,Session() 返回的是一个threading.local()对象的成员变量,threading.local()对象只有在线程内部才能实现线程隔离,因此只能放在run()函数里,而不能作为类成员变量。

如果按照错误示例来运行,所有线程其实公用了一个session,没有做到线程隔离,session.commit()操作会互相影响,我们原本只想将thread-9中的数据插入,结果会发现,所有线程中的数据全部被插入。

参考:

https://www.cnblogs.com/1a2a/p/8278698.html

http://blog.csdn.net/kikaylee/article/details/53232920
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: