SqlAlchemy 中操作数据库时session和scoped_session的区别

原生session:

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy应用.models import Users

engine = create_engine(
    "mysql+pymysql://root:[email protected]:3306/pro6?charset=utf8",
    max_overflow=0,  # 超过连接池大小外最多创建的连接
    pool_size=5,  # 连接池大小
)

#from sqlalchemy.orm.session import Session

SessionF = sessionmaker(bind=engine)
session = SessionF()

print(session)

obj1 = Users(name=‘ctz‘, email=‘[email protected]‘, extra=‘aaaa‘)

session.add(obj1)

session.commit()
session.close()

问题:由于无法提供线程共享功能,所以在开发时要注意,要给每个线程都创建自己的session

打印sesion可知他是sqlalchemy.orm.session.Session的对象

查看Session的源码 可得到:

class Session(_SessionClassMethods):
    """Manages persistence operations for ORM-mapped objects.

    The Session‘s usage paradigm is described at :doc:`/orm/session`.

    """

    public_methods = (
        ‘__contains__‘, ‘__iter__‘, ‘add‘, ‘add_all‘, ‘begin‘, ‘begin_nested‘,
        ‘close‘, ‘commit‘, ‘connection‘, ‘delete‘, ‘execute‘, ‘expire‘,
        ‘expire_all‘, ‘expunge‘, ‘expunge_all‘, ‘flush‘, ‘get_bind‘,
        ‘is_modified‘, ‘bulk_save_objects‘, ‘bulk_insert_mappings‘,
        ‘bulk_update_mappings‘,
        ‘merge‘, ‘query‘, ‘refresh‘, ‘rollback‘,
        ‘scalar‘)

2.scoped_session

from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy应用.models import Users
from sqlalchemy.orm import scoped_session

engine=create_engine(
    "mysql+pymysql://root:[email protected]:3306/pro6?charset=utf8",
    max_overflow=0,  # 超过连接池大小外最多创建的连接
    pool_size=5,  # 连接池大小
)

SessionF=sessionmaker(bind=engine)

#scoped_session封装了两个值 Session 和 registry,registry加括号就执行了ThreadLocalRegistry的__call__方法,如果

# 当前本地线程中有session就返回session,没有就将session添加到了本地线程

#self.registry()=session
session=scoped_session(SessionF)

print(session)
obj1=Users(name=‘ctz‘,email=‘[email protected]‘,extra=‘aaaa‘)

session.remove()
session.query_property()

优点:支持线程安全,为每个线程都创建一个session:

两种方式:通过本地线程Threading.Local()和创建唯一标识的方法(参考flask请求源码)

源码分析:

首先我们在scoped_session中放入了Sesion对象

SessionF=sessionmaker(bind=engine)
session=scoped_session(Session)

一、scoped_session类中
class scoped_session(object):
    session_factory = None
    def __init__(self, session_factory, scopefunc=None):

        #传递过来的那个Session对象
        self.session_factory = session_factory
        #scopefunc唯一标示函数
        if scopefunc:
            self.registry = ScopedRegistry(session_factory, scopefunc)
        else:
            self.registry = ThreadLocalRegistry(session_factory)

第一次进来scopefunc唯一标识为None,我们将Session作为参数传递到ThreadLocalRegistry中,

ThreadLocalRegistry类中

class ThreadLocalRegistry(ScopedRegistry):
    """A :class:`.ScopedRegistry` that uses a ``threading.local()``
    variable for storage.

    """

    def __init__(self, createfunc):
        #传递过来的那个Session对象
        self.createfunc = createfunc
        self.registry = threading.local()
     #scoped_session.registry()后执行
    def __call__(self):
        try:            #如果本地线程中有值的话直接将值返回,
            return self.registry.value
        except AttributeError:            #没有值的话就示例话Session(),并将他存到本地线程中,并把实例的对象返回
            #相当于Session()后的对象加到了本地线程中
            val = self.registry.value = self.createfunc()
            return val

其中__call__()只有当scoped_session.registry加括号执行

那我们怎么调用那些方法呢?

def instrument(name):
    def do(self, *args, **kwargs):
        return getattr(self.registry(), name)(*args, **kwargs)
    return do

for meth in Session.public_methods:
    setattr(scoped_session, meth, instrument(meth))

其中 Session就是sqlalchemy.orm.session.Session

 public_methods = (
        ‘__contains__‘, ‘__iter__‘, ‘add‘, ‘add_all‘, ‘begin‘, ‘begin_nested‘,
        ‘close‘, ‘commit‘, ‘connection‘, ‘delete‘, ‘execute‘, ‘expire‘,
        ‘expire_all‘, ‘expunge‘, ‘expunge_all‘, ‘flush‘, ‘get_bind‘,
        ‘is_modified‘, ‘bulk_save_objects‘, ‘bulk_insert_mappings‘,
        ‘bulk_update_mappings‘,
        ‘merge‘, ‘query‘, ‘refresh‘, ‘rollback‘,
        ‘scalar‘)

在instrument函数中

self.registry()帮我们执行了ThreadLocalRegistry中的___call__方法,拿到了sesion对象

方法源码示例:
 def has(self):
        return hasattr(self.registry, "value")
    def remove(self):
        if self.registry.has():
            self.registry().close()
        self.registry.clear()

实际两种方式原理都是一样的都是第一种,只是第二种将session放到了本地线程中,为每一个进程都设置了一个session,实现了线程安全

原文地址:https://www.cnblogs.com/ctztake/p/8277372.html

时间: 2024-10-29 04:53:43

SqlAlchemy 中操作数据库时session和scoped_session的区别的相关文章

SQLAlchemy中Model.query和session.query(Model)的区别

我们使用Flask 0.11.1,Flask-SQLAlchemy 2.1使用PostgreSQL作为DBMS. 示例使用以下代码更新数据库中的数据: entry = Entry.query.get(1) entry.name = 'New name' db.session.commit() 从Flask shell执行时,这完全正常,因此数据库已正确配置.现在,我们的控制器用于更新条目,略微简化(没有验证和其他样板),如下所示: def details(id): entry = Entry.q

{Django基础八之cookie和session}一 会话跟踪 二 cookie 三 django中操作cookie 四 session 五 django中操作session

本节目录 一 会话跟踪 二 cookie 三 django中操作cookie 四 session 五 django中操作session 六 xxx 七 xxx 八 xxx 一 会话跟踪 我们需要先了解一下什么是会话!可以把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应.例如你给10086打个电话,你就是客户端,而10086服务人员就是服务器了.从双方接通电话那一刻起,会话就开始了,到某一方挂断电话表示会话结束.在通话过程中,你会向10086发出多个请求,那么这多个请

有关网站中操作数据库的几种方法的使用情况

c# 数据查询输出 1 .使用 ExecuteReader() 操作数据库 2.使用ExecuteNonQuery()操作数据库3.使用ExecuteScalar()操作数据库4.使用DataSet 数据集插入记录.更新数据. 1.使用ExecuteReader()操作数据库,执行查询操作的利器 ExecuteReader相比与DataSet而言,DataReader 具有较快的访问能力,并且能够使用较少的服务器资源.DataReader对象提供了“游标”形式的读取方法,当从结果中读取了一行,则

在SQL SERVER 2005中还原数据库时出现错误:system.data.sqlclient.sqlerror 媒体集有 2 个媒体簇 但只提供了 1 个。必须提供所有成员。 (microsoft.sqlserver.smo)

问题:在SQL SERVER 2005中还原数据库时出现错误:system.data.sqlclient.sqlerror 媒体集有 2 个媒体簇 但只提供了 1 个.必须提供所有成员. (microsoft.sqlserver.smo) 原因:由于备份时,没有去掉默认的备份路径(C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Backup\backup.bak),而又添加了一个新的路径,结果备份了两份,但它们之间彼此依赖,所以没有办法恢复

在php中定义常量时,const与define的区别

[问]在php中定义常量时,const与define的区别? [答]使用const使得代码简单易读,const本身就是一个语言结构,而define是一个函数.另外const在编译时要比define快很多. (1).const用于类成员变量的定义,一经定义,不可修改.define不可用于类成员变量的定义,可用于全局常量. (2).const可在类中使用,define不能. (3).const不能在条件语句中定义常量. 例如: if (...){ const FOO = 'BAR';  // 无效的

C#中操作数据库技术之ExecuteNonQuery用法

最近在补基础知识,刚好补到C#中对数据库操作的一些技术,今天学习了ExecuteNonQuery的东西,看自己项目维护项目的代码和网上资料查询,基本上搞懂了ExecuteNonQuery的用法,小小的做个总结,供以后查阅. ExecuteNonQuery方法主要用来更新数据,当然也可以用来执行目标操作(例如查询数据库的结构或者创建诸如表等的数据库对象).通常用它来执行insert.update.delete语句,在不使用Dataset的情况下更改数据库中的数据.select语句不适合Execut

第四篇:python操作数据库时的传参问题

python在操作数据库执行sql的时候我们经常会遇到传参问题,以下是我总结的几种方法: 1.格式化字符串 city = 'beijing'cur.execute("SELECT * FROM %s WHERE city = %s", city) 2.使用字典传递 sql = "INSERT INTO user VALUES(%(username)s, %(password)s, %(email)s)"value = {"username":zh

Android开发中使用数据库时出现java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.

最近在开发一个 App 的时候用到了数据库,可是在使用数据库的时候就出现了一些问题,在我查询表中的一些信息时出现了一下问题: Caused by: java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed. at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(

Servlet中操作数据库

以下内容引用自http://wiki.jikexueyuan.com/project/servlet/database-access.html: 前提先新建数据库及插入模拟数据: create table Employees ( id int not null, age int not null, first varchar (255), last varchar (255) ); INSERT INTO Employees VALUES (100, 18, 'Zara', 'Ali'); IN