原生session:

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy应用.models import Users engine = create_engine(
"mysql+pymysql://root:root@127.0.0.1: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='49274573@qq.com', 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:root@127.0.0.1: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='49274573@qq.com',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,实现了线程安全

SqlAlchemy 中操作数据库时session和scoped_session的区别(源码分析)的更多相关文章

  1. flask 源码专题(五):SqlAlchemy 中操作数据库时session和scoped_session的区别

    1原生session: from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine from sqlalc ...

  2. netty中的发动机--EventLoop及其实现类NioEventLoop的源码分析

    EventLoop 在之前介绍Bootstrap的初始化以及启动过程时,我们多次接触了NioEventLoopGroup这个类,关于这个类的理解,还需要了解netty的线程模型.NioEventLoo ...

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

    我们使用Flask 0.11.1,Flask-SQLAlchemy 2.1使用PostgreSQL作为DBMS. 示例使用以下代码更新数据库中的数据: entry = Entry.query.get( ...

  4. Disruptor中shutdown方法失效,及产生的不确定性源码分析

    版权声明:原创作品,谢绝转载!否则将追究法律责任. Disruptor框架是一个优秀的并发框架,利用RingBuffer中的预分配内存实现内存的可重复利用,降低了GC的频率. 具体关于Disrupto ...

  5. 开源分布式数据库中间件MyCat源码分析系列

    MyCat是当下很火的开源分布式数据库中间件,特意花费了一些精力研究其实现方式与内部机制,在此针对某些较为重要的源码进行粗浅的分析,希望与感兴趣的朋友交流探讨. 本源码分析系列主要针对代码实现,配置. ...

  6. 深入理解 Node.js 中 EventEmitter源码分析(3.0.0版本)

    events模块对外提供了一个 EventEmitter 对象,即:events.EventEmitter. EventEmitter 是NodeJS的核心模块events中的类,用于对NodeJS中 ...

  7. 第二百八十九节,MySQL数据库-ORM之sqlalchemy模块操作数据库

    MySQL数据库-ORM之sqlalchemy模块操作数据库 sqlalchemy第三方模块 sqlalchemysqlalchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API ...

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

    Django基础八之cookie和session 本节目录 一 会话跟踪 二 cookie 三 django中操作cookie 四 session 五 django中操作session 六 xxx 七 ...

  9. Kafka中操作topic时 Error:Failed to parse the broker info from zookeeper

      Kafka中操作topic时 Error: Failed to parse the broker info from zookeeper 1.问题描述   2.问题原因     kafka在启动后 ...

随机推荐

  1. 第二百六十八节,Tornado框架-路由映射之二级域名支持,html模板继承以及导入

    Tornado框架-路由映射之二级域名支持,html模板继承以及导入 二级域名路由映射add_handlers()设置二级域名路由映射 注意:二级域名需要结合服务器ip绑定域名 框架引擎 #!/usr ...

  2. mysql -- 存储过程中 declare 和 set 定义变量的区别

    mysql存储过程中,定义变量有两种方式:1.使用set或select直接赋值,变量名以 @ 开头.例如:set @var=1;可以在一个会话的任何地方声明,作用域是整个会话,称为会话变量. 2.以 ...

  3. c# http请求,获取非200时的响应体

    HttpWebResponse res = null; try { res = request.GetResponse() as HttpWebResponse; } catch (WebExcept ...

  4. Yii2.0实现微信公众号后台开发

    接入微信 Yii2后台配置 1.在app/config/params.php中配置token参数 return [ //微信接入 'wechat' =>[ 'token' => 'your ...

  5. JavaScript的parseint()函数

    定义和用法 parseInt() 函数可解析一个字符串,并返回一个整数. 语法 parseInt(string, radix) 参数 描述 string 必选项.要转换为数字的字符串. radix 可 ...

  6. PowerShell中的配置文件

    http://www.cnblogs.com/ceachy/archive/2013/03/01/PowerShell_Profile.html

  7. python3----datetime模块分析

    datetime模块用于是date和time模块的合集,datetime有两个常量,MAXYEAR和MINYEAR,分别是9999和1. datetime模块定义了5个类,分别是 1.datetime ...

  8. ios开发之--CGRect/CGSize/CGPoint/CGVector/CGAffineTransform/UIEdgeInsets/UIOffset和NSString之间的转换

    仅做记录,一个函数和字符串之间的互相转换 方法如下: UIKIT_EXTERN NSString *NSStringFromCGPoint(CGPoint point); UIKIT_EXTERN N ...

  9. virtualbox虚拟机Linux系统与本地windows系统共享文件方法

    转自:http://jingyan.baidu.com/article/2fb0ba40541a5900f2ec5f07.html

  10. JSP内置对象——application,page,pageContext,config,Exception

    application对象application对象实现了用户数据的共享,可存放全局变量.application开始于服务器的启动,终止于服务器的关闭.在用户的前后链接或不同用户之间的连接中,可以对a ...