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

摘要:
如何避免使用SQLAlchemy、连接池和create_当引擎创建引擎时,如果默认情况下未指定连接池设置,SQLAlchem通常会使用QueuePool绑定到新创建的引擎。附加适当的连接池参数。该连接将由QueuePool连接池管理和重用。最初维护的数据库连接失败。要禁用SQLAlchemy提供的数据库连接池,只需调用create_Engine指定连接池为NullPool,SQLAlchemi将在close()后立即执行会话Disconnect the database。当然,如果会话对象被销毁,但会话。如果未调用close(),则在程序终止之前不会断开数据库连接。

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

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都相当于一个connection
        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中的数据插入,结果会发现,所有线程中的数据全部被插入。

 如何避免使用SQLAlchemy使用连接池

在使用 create_engine创建引擎时,如果默认不指定连接池设置的话,一般情况下,SQLAlchemy会使用一个 QueuePool绑定在新创建的引擎上。并附上合适的连接池参数。

在以默认的方法create_engine时(如下),就会创建一个带连接池的引擎。

engine = create_engine('postgresql://postgres@127.0.0.1/dbname')
在这种情况下,当你使用了session后就算显式地调用session.close(),也不能把连接关闭。连接会由QueuePool连接池进行管理并复用。

这种特性在一般情况下并不会有问题,不过当数据库服务器因为一些原因进行了重启的话。最初保持的数据库连接就失效了。随后进行的session.query()等方法就会抛出异常导致程序出错。

如果想禁用SQLAlchemy提供的数据库连接池,只需要在调用create_engine是指定连接池为NullPool,SQLAlchemy就会在执行session.close()后立刻断开数据库连接。当然,如果session对象被析构但是没有被调用session.close(),则数据库连接不会被断开,直到程序终止。

下面的代码就可以避免SQLAlchemy使用连接池:

#!/usr/bin/env python
#-*- coding: utf-8 -*-
 
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import NullPool
 
engine = create_engine('postgresql://postgres@127.0.0.1/dbname',
  poolclass=NullPool)
Session = sessionmaker(bind=engine)
session = Session()
usr_obj_list = session.query(UsrObj).all()
print usr_obj_list[0].id
session.close()

https://blog.csdn.net/daijiguo/article/details/79486294

https://blog.csdn.net/weiwangchao_/article/details/80185009

参考:

https://www.cnblogs.com/1a2a/p/8278698.html 
http://blog.csdn.net/kikaylee/article/details/53232920

 

免责声明:文章转载自《数据库连接池SQLAlchemy中多线程安全问题》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇用Delphi开发视频聊天软件主流服务器虚拟化技术简单使用——Xen(二)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

安卓多线程的实现

有以下几种方式: 1)Activity.runOnUiThread(Runnable) 2)View.post(Runnable) ;View.postDelay(Runnable , long) 3)Handler 4)AsyncTask Android是单线程模型,这意味着Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行,所以你...

JSTL 标签库详细介绍资料

前言从jsp 1.1规范开始,jsp就支持在jsp中使用自定义标签了,自定义标签的广泛使用造成了程序员重复定义,这样就促成了jstl(javaserver pages standard tag library)的诞生。因为工作中需要用到jstl,但网上却苦于找不到有关jstl的中文资料,所以就有了这篇文章。jstl简介jstl是一个不断完善的开放源代码的j...

ASP.NET 中实现会话状态的基础

简介 在 Web 应用程序这样的无状态环境中,了解会话状态的概念并没有实际的意义。尽管如此,有效的状态管理对于大多数 Web 应用程序来说都是一个必备的功能。Microsoft® ASP.NET 以及许多其他服务器端编程环境都提供了一个抽象层,允许应用程序基于每个用户和每个应用程序存储持久性数据。 需要特别注意的是,Web 应用程序的会话状态是应用程序在不...

windows线程yield以及Sleep(0)和SwitchToThread之间的区别

C++的自定义线程函数内调用了一个自定义的yield()接口。 在windows上是调用了SwitchToThread来实现的,linux是pthread_yield实现的。 Sleep(0):时间片只能让给优先级相同或更高的线程; SwitchToThread():只要有可调度线程,即便优先级较低,也会让其调度。 下面是MSDN上对Sleep函数的描述:...

Java Web基础 --- Servlet 综述(理论篇)

摘要:   Web 技术成为当今主流的互联网 Web 应用技术之一,而 Servlet 是 Java Web 技术的核心基础。本文首先从请求/响应架构应用的大背景谈起 Servlet 的由来,明确 Servlet 的产生动机,并揭示了 Servlet 的本质以及其在标准MVC模式中所扮演的角色。紧接着,给出了 Servlet族的继承结构,并对族内的接口和抽...

libevent 和 libev 提高网络应用性能

构建现代的服务器应用程序需要以某种方法同时接收数百、数千甚至数万个事件,无论它们是内部请求还是网络连接,都要有效地处理它们的操作。有许多解决方 案,但是 libevent 库和 libev 库能够大大提高性能和事件处理能力。在本文中,我们要讨论在 UNIX® 应用程序中使用和部署这些解决方案所用的基本结构和方法。libev 和 libevent 都可以在高...