SQLAlchemy 中的 Session、sessionmaker、scoped_session

SQLAlchemy 中的 Session、sessionmaker、scoped_session

目录

  • 一、关于 Session
    • 1. Session是缓存吗?
    • 2. Session作用:
    • 3. Session生命周期:
    • 4. Session什么时候创建,提交,关闭?
    • 4. 获取一个Session:
    • 5. 关于SQLAlchemy 的 create_engine:
    • 6. 关于线程安全:
  • 二、单线程下 scoped_session 对创建 Session 的影响
    • 1. 两个 Session 添加同一个对象
    • 2. 不同的 Session 添加不同的对象
    • 3. 用 scoped_session 创建 Session
  • 三、多线程下 scoped_session 对创建 Session 的影响
    • 1. 当不用 scoped_session 时:
    • 2. 当使用 scoped_session 时:

一、关于 Session

Session 其实 就是一个会话, 可以和数据库打交道的一个会话

在一般的意义上, 会话建立与数据库的所有对话,并为你在其生命周期中加载或关联的所有对象表示一个“等待区”。他提供了一个入口点获得查询对象, 向数据库发送查询,使用会话对象的当前数据库连接, 将结果行填充在对象中, 然后存储在会话中, 在这种结构中称为身份映射 – 这种数据结构维护了每一个副本的唯一, 这种唯一意味着一个对象只能有一个特殊的唯一主键。

会话以基本无状态的形式开始,一旦发出查询或其他对象被持久化,它就会从一个引擎申请连接资源,该引擎要么与会话本身相关联,要么与正在操作的映射对象相关联。此连接标识正在进行的事务, 在会话提交或回滚其挂起状态之前,该事务一直有效。

会话中维护的所有变化的对象都会被跟踪 - 在再次查询数据库或提交当前事务之前, 它将刷新对数据库的所有更改, 这被称为工作模式单元。

在使用会话时候,最重要的是要注意与它相关联的对象是会话所持有的事务的代理对象 - 为了保持同步,有各种各样的事件会导致对象重新访问数据库。可能从会话中分离对象并继续使用他们,尽管这种做法有其局限性。但是通常来说,当你希望再次使用分离的对象时候,你会将他们与另一个会话重新关联起来, 以便他们能够恢复表示数据库状态的正常任务。


1. Session是缓存吗?

可能会将这里的session与http中的session搞混,需要注意的是,它有点用作缓存,因为它实现了 身份映射 模式,并存储了键入其主键的对象。但是,它不执行任何类型的查询缓存。
此外,默认情况下,Session使用弱引用存储对象实例。这也违背了将Session用作缓存的目的。关于session强应用下次再讨论。

2. Session作用:

1. session创建和管理数据库连接的会话
2. model object 通过session对象访问数据库,并把访问到的数据以 Identity Map的方式,映射到Model object中

3. Session生命周期:

1. session在刚被创建的时候,还没有和任何model object 绑定,可认为是无状态的
2. session 接受到query查询语句, 执行的结果或保持或者关联到session中
3. 任意数量的model object被创建,并绑定到session中,session会管理这些对象
4. 一旦session 里面的objects 有变化,那可是要commit/rollback提交或者放弃changs

4. Session什么时候创建,提交,关闭?

一般来说,session在需要访问数据库的时候创建,在session访问数据库的时候,准确来说,应该是“add/update/delete”数据库的时候,会开启database transaction。假设没有修改autocommit的默认值(False), 那么,database transaction 一直会保持,只有等到session发生rolled back、committed、或者closed的时候才结束,一般建议,当database transaction结束的时候,同时close session,以保证,每次发起请求,都会创建一个新的session特别是对web应用来说,发起一个请求,若请求使用到Session访问数据库,则创建session,处理完这个请求后,关闭session

4. 获取一个Session:

Session 是一个直接实例化的常规的Python 类。然而, 为了标准会会话的配置和获取方式, sessionmaker 类通常用于创建顶级会话配置, 然后可以在整个应用程序中使用它, 就不需要重复配置参数。

下面是sessionmaker 的使用方式

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker# 创建连接数据库的引擎,session连接数据库需要
my_engine = create_engine('mysql+pymysql://root:123456@localhost/my_db')# 创建一个配置过的Session类
Session = sessionmaker(bind=my_engine)# 实例化一个session
db_session = Session()# 使用session
myobject = MyObject('foo', 'bar')
db_session.add(myobject)
db_session.commit()

在上面,该sessionmaker()创建了一个工厂类,在创建这个工厂类时我们配置了参数绑定了引擎。将其赋值给Session。每次实例化Session都会创建一个绑定了引擎的Session。这样这个session在访问数据库时都会通过这个绑定好的引擎来获取连接资源
当你编写应用程序时, 请将sessionmaker 工厂放在全局级别,视作应用程序配置的一部分。例如:应用程序包中有三个.py文件,您可以将该sessionmaker行放在__init__.py文件中; 在其他模块“from mypackage import Session”。这样,所有的Session()的配置都由该配置中心控制。

5. 关于SQLAlchemy 的 create_engine:

直接只用 create_engine 时,就会创建一个带连接池的引擎:

my_engine = create_engine('mysql+pymysql://root:123456@localhost/my_db')

创建一个session,连接池会分配一个connection。当session在使用后显示地调用 session.close(),也不能把这个连接关闭,而是由由QueuePool连接池管理并复用连接。

确保 session 在使用完成后用 session.close、session.commit 或 session.rollback 把连接还回 pool,这是一个必须在意的习惯。

关于SQLAlchemy 数据库连接池:

session 和 connection 不是相同的东西, session 使用连接来操作数据库,一旦任务完成 session 会将数据库 connection 交还给 pool。在使用 create_engine 创建引擎时,如果默认不指定连接池设置的话,一般情况下,SQLAlchemy 会使用一个 QueuePool 绑定在新创建的引擎上。并附上合适的连接池参数

create_engine() 函数和连接池相关的参数有:

  • pool_recycle, 默认为 -1, 推荐设置为 7200, 即如果 connection 空闲了 7200 秒,自动重新获取,以防止 connection 被 db server 关闭。
  • pool_size=5, 连接数大小,默认为 5,正式环境该数值太小,需根据实际情况调大
  • max_overflow=10, 超出 pool_size 后可允许的最大连接数,默认为 10, 这 10 个连接在使用过后,不放在 pool 中,而是被真正关闭的。
  • pool_timeout=30, 获取连接的超时阈值,默认为 30 秒

SQLAlchemy不使用连接池:
在创建引擎时指定参数 poolclass=NullPool 即禁用了SQLAlchemy提供的数据库连接池。SQLAlchemy 就会在执行 session.close() 后立刻断开数据库连接。当然,如果没有被调用 session.close(),则数据库连接不会被断开,直到程序终止。

my_engine = create_engine('mysql+pymysql://root:123456@localhost/my_db',poolclass=NullPool)

关于 SQLAlchemy 的 engine ,这里有一篇文章写的很好:http://sunnyingit.github.io/book/section_python/SQLalchemy-engine.html

6. 关于线程安全:

session不是线程安全的,在多线程的环境中,默认情况下,多个线程将会共享同一个session。试想一下,假设A线程正在使用session处理数据库,B线程已经执行完成,把session给close了,那么此时A在使用session就会报错,怎么避免这个问题?

1. 可以考虑在这些线程之间共享Session及其对象。但是应用程序需要确保实现正确的锁定方案,以便多个线程不会同时访问Session或其状态。SQLAlchemy 中的 scoped_session 就可以证线程安全,下面会有讨论。
2. 为每个并发线程维护一个会话,而不是将对象从一个Session复制到另一个Session,通常使用Session.merge()方法将对象的状态复制到一个不同Session的新的本地对象中。

二、单线程下 scoped_session 对创建 Session 的影响

上面简单介绍了sessionmaker的作用,下面开始探讨 scoped_session 对创建 Session 的影响。现在先探讨单线程情况。


先声明待会实验用的模型:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy import create_engineBase = declarative_base
engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/my_db?charset=utf8mb4")class Person(Base):__tablename__ = 'Person'id = Column(Integer, primary_key=True, autoincrement=True)name = Column(String(length=64), comment='姓名')mobile = Column(String(length=13), comment='手机号')id_card_number = Column(String(length=64), comment='身份证')def __str__(self):return '%s(name=%r,mobile=%r,id_card_number=%r)' % (self.__class__.__name__,self.name,self.mobile,self.id_card_number)# 在数据库中创建模型对象的表
Base.metadata.create_all(engine)

1. 两个 Session 添加同一个对象

1.1 在 commit 之前添加:


from sqlalchemy.orm import sessionmaker, scoped_sessionsession_factory = sessionmaker(bind=engine)
# engine 在上面已经创建好了person = Person(name='frank-' + 'job3', mobile='111111', id_card_number='123456789')Session= session_factory()
s1= session_factory()
# s1 : <sqlalchemy.orm.session.Session object at 0x107ec8c18>s2 = session_factory() 
# s2 : <sqlalchemy.orm.session.Session object at 0x107ee3ac8>print(s1 is s2)
# Falseid(s1),id(s2)
# 4427910168, 4428020424s1.add(person)
s2.add(person)
# 会报错!
# sqlalchemy.exc.InvalidRequestError: Object '<Person at 0x22beb14bf60>' is already attached to session '2' (this is '3')

结论:

通过 sessionmaker 工厂创建了两个 Session ,而且可以看到 s1 s2 是两个不同的 Session 。
在 s1 添加 person 后,继续使用 s2 添加 person 报错. 说 person 这个对象 已经和 另一个 Session 关联一起来了, 所以再次关联另一个 Session 就会报错。

1.2 在 commit 之后添加:

即在上面代码的 s1.add(person) 之后, s1.commit() ,然后再 s2.add(persion)
这里就没帖代码了。

结论:

即使在 s1 提交之后,s2 再去添加 person 也会发生错误,但 s1 的提交是成功了的,数据 person 已经存放在数据库了。
当 s1 添加 person 并提交,然后关闭 s1 ,s2再去添加并提交 person 数据库,这不会报错,但是数据库也不会出现两条 person 数据。

1.3 再 close 之后添加:

p = Person(name='frank', mobile='11111111', id_card_number='123456789')s1.add(p)
s1.commit()s2.add(p)
s2.commit()# 也会报错!!!
# sqlalchemy.exc.InvalidRequestError: Object '<Person at 0x21207e3e128>' is already attached to session '2' (this is '3')p = Person(name='frankcc', mobile='1111111122', id_card_number='1234567890')s1.add(p)
s1.commit()
s1.close()
s2.add(p)
s2.commit()# 不会报错

结论:

s1 关闭之后, s2再去添加提交同一个对象,不会报错,但是数据库值有一条 person 数据。

2. 不同的 Session 添加不同的对象

person4 = Person(name='frank-' + 'job4', mobile='4444444444', id_card_number='123456789')
person1 = Person(name='frank-' + 'job1', mobile='111111', id_card_number='123456789')s1.add(person1)
s2.add(person4)
s1.commit()  # 提交数据
s2.commit()  # 提交数据, 写入数据库

结论:

当然,s1 ,s2 添加提交不同的对象,不会出错。在数据库成功新增数据。 

mysql> select * from person;
+----+------------+------------+----------------+
| id | name       | mobile     | id_card_number |
+----+------------+------------+----------------+
|  1 | frank-job1 | 111111     | 123456789      |
|  2 | frank-job4 | 4444444444 | 123456789      |
+----+------------+------------+----------------+
2 rows in set (0.00 sec)

以上说明:

一个对象一旦被一个 Session 添加,除非关闭这个 Session ,不然其他的 Session 无法添加这个对象。
一个 Session 添加并提交一个对象,然后关闭该 Session ,其他的 Session 可以添加并提交这个对象,但是数据库并不会有这条数据。

3. 用 scoped_session 创建 Session


session_factory = sessionmaker(bind=engine)
Session = scoped_session(session_factory)s1 = Session()
# <sqlalchemy.orm.session.Session object at 0x0000020E58690240>s2 = Session()
# <sqlalchemy.orm.session.Session object at 0x0000020E58690240>print(s1 is s2)
# Truep = Person(name='frankaaabb', mobile='1111111122233', id_card_number='12345678900099')s1.add(p)
s2.add(p)
s2.commit()

结论:

可以看到,通过scoped_session再去创建 Session ,返回的是同一个 Session 。
scoped_session类似单例模式,当我们调用使用的时候,会先在Registry里找找之前是否已经创建Session,未创建则创建 Session ,已创建则直接返回。

三、多线程下 scoped_session 对创建 Session 的影响

这里探讨在多线程下使用 scoped_session 与不使用 scoped_session 的情况


1. 当不用 scoped_session 时:

当不使用 scoped_session 时,也分两种情况,是否创建全局性 Session

1.1 多线程下不设置 Session 为全局变量


session_factory = sessionmaker(bind=engine)
Session = session_factorydef job(name):session = Session()print(f"id session:{id(session)}")person = Person(name='frank-' + name, mobile='111111', id_card_number='123456789')print(f"{name} person is add..")session.add(person)time.sleep(1)if name == 'job3':# 线程3 提交, 其他线程不提交.session.commit()session.close()if __name__ == '__main__':thread_list = []# 创建5个线程for i in range(5):name = 'job' + str(i)t = threading.Thread(target=job, name=name, args=(name,))thread_list.append(t)for t in thread_list:t.start()for t in thread_list:t.join()

结论:

每个线程下的 Session 都是不同的 Session
数据库成功新增了线程3提交的数据,其他的线程中的数据并没有提交到数据库中去。

id session:2557871997392
job0 person is add..
id session:2557871998064
job1 person is add..
id session:2557871998568
job2 person is add..
id session:2557871999072
job3 person is add..
id session:2557871999688
job4 person is add..mysql> select * from person;
+----+------------+--------+----------------+
| id | name       | mobile | id_card_number |
+----+------------+--------+----------------+
| 14 | frank-job3 | 111111 | 123456789      |
+----+------------+--------+----------------+
1 row in set (0.00 sec)

1.2 在多线程下用全局 Session


session_factory = sessionmaker(bind=engine)
Session = session_factory
session = Session()def job(name):global sessionprint(f"id session:{id(session)}")person = Person(name='frank-' + name, mobile='111111', id_card_number='123456789')print(f"{name} person is add..")session.add(person)time.sleep(1)if name == 'job3':# 线程3 提交, 其他线程不提交.session.commit()session.close()if __name__ == '__main__':thread_list = []# 创建5个线程for i in range(5):name = 'job' + str(i)t = threading.Thread(target=job, name=name, args=(name,))thread_list.append(t)for t in thread_list:t.start()for t in thread_list:t.join()

结论:

全部线程下的 Session 都时同一个 Session
每个线程下的数据都被提交到了数据库

id session:2737857674824
job0 person is add..
id session:2737857674824
job1 person is add..
id session:2737857674824
job2 person is add..
id session:2737857674824
job3 person is add..
id session:2737857674824
job4 person is add..mysql> select * from person;
+----+------------+--------+----------------+
| id | name       | mobile | id_card_number |
+----+------------+--------+----------------+
| 15 | frank-job0 | 111111 | 123456789      |
| 16 | frank-job2 | 111111 | 123456789      |
| 17 | frank-job1 | 111111 | 123456789      |
| 18 | frank-job3 | 111111 | 123456789      |
| 19 | frank-job4 | 111111 | 123456789      |
+----+------------+--------+----------------+
5 rows in set (0.00 sec)

2. 当使用 scoped_session 时:

2.1 多线程下不设置 Session 为全局变量


session_factory = sessionmaker(bind=engine)
Session = scoped_session(session_factory)def job(name):session = Session()print(f"id session:{id(session)}")person = Person(name='frank-' + name, mobile='111111', id_card_number='123456789')print(f"{name} person is add..")session.add(person)time.sleep(1)if name == 'job3':# 线程3 提交, 其他线程不提交.session.commit()session.close()if __name__ == '__main__':thread_list = []# 创建5个线程for i in range(5):name = 'job' + str(i)t = threading.Thread(target=job, name=name, args=(name,))thread_list.append(t)for t in thread_list:t.start()for t in thread_list:t.join()

结论:

每个线程下的 Session 都不相同
只有线程3下的数据被提交到了数据库

id session:2173841850832
job0 person is add..
id session:2173841851504
job1 person is add..
id session:2173841851896
job2 person is add..
id session:2173841852008
job3 person is add..
id session:2173841853128
job4 person is add..mysql> select * from person;
+----+------------+--------+----------------+
| id | name       | mobile | id_card_number |
+----+------------+--------+----------------+
| 32 | frank-job3 | 111111 | 123456789      |
+----+------------+--------+----------------+
1 row in set (0.00 sec)

2.2 多线程下设置 Session 为全局变量


session_factory = sessionmaker(bind=engine)
Session = scoped_session(session_factory)
session = Session()def job(name):global sessionprint(f"id session:{id(session)}")person = Person(name='frank-' + name, mobile='111111', id_card_number='123456789')print(f"{name} person is add..")session.add(person)time.sleep(1)if name == 'job3':# 线程3 提交, 其他线程不提交.session.commit()session.close()if __name__ == '__main__':thread_list = []# 创建5个线程for i in range(5):name = 'job' + str(i)t = threading.Thread(target=job, name=name, args=(name,))thread_list.append(t)for t in thread_list:t.start()for t in thread_list:t.join()

结论:

每个线程下的 Session 是同一个 Session
每个线程下的数据都没提交到了数据库

id session:2810724382032
job0 person is add..
id session:2810724382032
job1 person is add..
id session:2810724382032
job2 person is add..
id session:2810724382032
job3 person is add..
id session:2810724382032
job4 person is add..mysql> select * from person;
+----+------------+--------+----------------+
| id | name       | mobile | id_card_number |
+----+------------+--------+----------------+
| 33 | frank-job0 | 111111 | 123456789      |
| 34 | frank-job2 | 111111 | 123456789      |
| 35 | frank-job1 | 111111 | 123456789      |
| 36 | frank-job3 | 111111 | 123456789      |
| 37 | frank-job4 | 111111 | 123456789      |
+----+------------+--------+----------------+
5 rows in set (0.00 sec)

以上说明:

在同一个线程中,有 scoped_session 的时候,返回的是同一个 Session 对象。
在多线程下,即使通过  scoped_session 创建Session,每个线程下的 Session 都是不一样的,每个线程都有一个属于自己的 Session 对象,这个对象只在本线程下共享。 
scoped_session 只有在单线程下才能发挥其作用。在多线程下显得没有什么作用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/456349.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

没有任何权力的“项目经理”该如何当?

2016.11.25 11:40* 字数 1454 阅读 108评论 0喜欢 1小王几月前被任命为项目经理&#xff0c;负责9个人的工作安排。工作上要对上负责&#xff0c;完成项目&#xff0c;可对下小王却没有对小组成员的工作考核权&#xff0c;也就是说&#xff0c;不能影响他们的收入。 图片发自简…

SparkSQL之Join原理

文章目录前言&#xff1a;Join背景介绍Join常见分类以及基本实现机制Hash JoinBroadcast Hash JoinShuffle Hash JoinSort-Merge Join总结前言&#xff1a; 写SQL的时候很多时候都有用到join语句&#xff0c;但是我们真的有仔细想过数据在join的过程到底是怎么样的吗&#xff…

SQLAlchemy中filter_by()和filter()的用法不同

filter_by() 和 filter() 的最主要的区别&#xff1a; 模块语法><&#xff08;大于和小于&#xff09;查询and_和or_查询filter_by()直接用属性名&#xff0c;比较用不支持不支持filter()用类名.属性名&#xff0c;比较用支持支持 谈 filter_by() 的语法之前先看下 filt…

python爬虫从入门到放弃(六)之 BeautifulSoup库的使用

上一篇文章的正则&#xff0c;其实对很多人来说用起来是不方便的&#xff0c;加上需要记很多规则&#xff0c;所以用起来不是特别熟练&#xff0c;而这节我们提到的beautifulsoup就是一个非常强大的工具&#xff0c;爬虫利器。 beautifulSoup “美味的汤&#xff0c;绿色的浓汤…

SparkHiveSQL中Join操作的谓词下推?

前言&#xff1a; SparkSQL和HiveSQL的Join操作中也有谓词下推&#xff1f;今天就通过大神的文章来了解下。同样&#xff0c;如有冒犯&#xff0c;请联系。 正文 上文简要介绍了Join在大数据领域中的使用背景以及常用的几种算法&#xff0d;broadcast hash join 、shuffle h…

【转载】通过金矿模型介绍动态规划 (动态规划入门)

先附上原文地址&#xff1a;http://www.cnblogs.com/sdjl/articles/1274312.html 通过金矿模型介绍动态规划 对于动态规划&#xff0c;每个刚接触的人都需要一段时间来理解&#xff0c;特别是第一次接触的时候总是想不通为什么这种方法可行&#xff0c;这篇文章就是为了…

flask模型中【外键】relationship的使用笔记

模型中relationship的使用笔记 模型.PY class User(db.Model):# __tablename__ user1 #定义表名id db.Column(db.Integer, primary_keyTrue, autoincrementTrue)username db.Column(db.String(10), nullableTrue)password db.Column(db.String(64), nullableTrue)phone …

六种方式实现生产者消费者(未完)

2019独角兽企业重金招聘Python工程师标准>>> 一、利用Object对象是wait和notify\notifyAll package com.jv.parallel.consumerandproducer.objectwait;public class Car {private volatile int flag 0;public void showConsumer(){System.out.println("I am a…

SQL中基于代价的优化

还记得笔者在上篇文章无意中挖的一个坑么&#xff1f;如若不知&#xff0c;强烈建议看官先行阅读前面两文&#xff0d;《SparkSQL Join原理》和《Join中竟然也有谓词下推?》 第一篇文章主要分析了大数据领域Join的三种基础算法以及各自的适用场景&#xff0c;第二篇文章在第一…

git如何解决冲突(代码托管在coding)

分支A提交合并请求到分支B&#xff0c;有冲突git fetch code 拉取远程仓库的其他分支代码&#xff08;我拉代码是remote add code所以这里是code,可以用git remote查看&#xff09;git checkout 分支A 切换到分支Agit pull code 分支A 拉取分支A代码git checkout 分支B 切换到分…

cookie和session之会话机制:   http 协议  ---》 无状态协议

设置cookie&#xff1a; 通过response对象&#xff1a; response make_response() response.set_cookie(key,value,max_age(单位second),expires(要求是detetime类型)) expires datetime(year2018,month11,day5) #expires是这么设置的 expires datetime.n…

Java Map 怎样实现Key 的唯一性?

大家都知道。在Map和Set不可存在反复元素&#xff1f; 可是对于内部的细节我们并不了解。今天我们就一块来 探讨一下&#xff01; 1 对于 HashMap HashSet 他们的底层数据结构的实现是&#xff1a;维护了一张 HashTable 。容器中的元素所有存储在Hashtable 中。他们再加入…

win10下安装pyspark及碰到的问题

文章目录前言安装过程Q1总结&#xff1a;前言 最近由于工作需要&#xff0c;需要了解下pyspark&#xff0c;所以就在win10环境下装了下&#xff0c;然后在pycharm中使用的时候碰到了一些问题。整个过程可谓是一波三折。下面一一道来。 安装过程 安装过程就不详细说了&#x…

解决AttributeError AttributeError: 'NoneType' object has no attribute 'filename'

原因忘记上传文件 表单需要加属性 enctype"multipart/form-data" 否则报错&#xff01;AttributeError AttributeError: NoneType object has no attribute filename enctype"multipart/form-data是设置表单的MIME编码。默认情况&#xff0c;这个编码格式是ap…

SQLAlchemy()分页器paginate方法

Flask的数据分页示例 用法&#xff1a; 1&#xff0c;首先写数据获取的视图函数&#xff0c;就像这样&#xff1a; # 首页 blog_bp.route(/, endpointindex) def index():#获取页数page request.args.get(page,1)paginate Article.query.paginate(pageint(page),per_page3)…

开源中国 2014 年源创会年度计划

时光总是从敲代码的指尖不经意地滑过&#xff0c;转眼2014年已快过去一半&#xff0c;OSC依然心怀着最初的梦想。 源创会&#xff0c;oscer的线下快乐大本营&#xff0c;我们仍在继续...... 聆听技术大牛讲解最前沿的技术&#xff0c;和同道中人切磋IT秘籍&#xff0c;吃点心侃…

互联网金融行业申请评分卡(A卡)简介

文章目录前言基本概念1、信用违约风险的基本概念什么是信用违约风险&#xff1a;组成部分违约的主体个贷中常用的违约定义M0&#xff0c;M1&#xff0c;M2的定义2、申请评分卡的重要性和特性信贷场景中的评分卡申请评分卡的概念为什么要开发申请评分卡评分卡的特性 &#xff08…

Flask的csrf_token的用法

在flask当中&#xff0c;flask-wtf模块时携带csrf校验的&#xff0c;只是需要开启&#xff1b; 如果不开启校验就不需要校验&#xff0c;但是那样不安全。 Csrf是针对与post请求的跨域限制&#xff0c;get请求没有作用 csrf_token的开启 在flask中开启csrf保护 from flask_…

dotty编译器语法特性之一交叉类型,联合类型和文本单例类型

2019独角兽企业重金招聘Python工程师标准>>> ###翻译&#xff1a;http://dotty.epfl.ch/docs/reference/intersection-types.html #交叉类型 trait Resettable {def reset(): this.type } trait Growable[T] {def add(x: T): this.type } def f(x: Resettable &…

【转】Zookeeper 安装和配置

转自&#xff1a;http://coolxing.iteye.com/blog/1871009 Zookeeper的安装和配置十分简单, 既可以配置成单机模式, 也可以配置成集群模式. 下面将分别进行介绍. 单机模式 1. 配置 点击这里下载zookeeper的安装包之后, 解压到合适目录. 进入zookeeper目录下的conf子目录, 创建z…