本篇导航:

面向对象部分知识点解析

1、子类继承父类__init__的三种方式

  1. class Dog(Animal): #子类 派生类
  2. def __init__(self,name,breed, life_value,aggr):
  3. # Animal.__init__(self,name,breed, life_value,aggr)#让子类执行父类的方法 就是父类名.方法名(参数),连self都得传
  4. super().__init__(name,life_value,aggr) #super关键字 ,都不用传self了,在新式类里的
  5. # super(Dog,self).__init__(name,life_value,aggr) #上面super是简写
  6. self.breed = breed
  7. def bite(self,person): #狗的派生方法
  8. person.life_value -= self.aggr
  9. def eat(self): #父类方法的重写
  10. super().eat()
  11. print('dog is eating')

2、对象通过索引设置值的三种方式

  1. class Foo(object):
  2. def __setitem__(self, key, value):
  3. print(key,value)
  4.  
  5. obj = Foo()
  6. obj["xxx"] = 123 #给对象赋值就会去执行__setitem__方法

重写__setitem__方法

  1. class Foo(dict):
  2. pass
  3.  
  4. obj = Foo()
  5. obj["xxx"] = 123
  6. print(obj)

继承dict

  1. class Foo(dict):
  2. def __init__(self,val):
  3. # dict.__init__(self, val)#继承父类方式一
  4. # super().__init__(val) #继承父类方式二
  5. super(Foo,self).__init__(val)#继承父类方式三
  6. obj = Foo({"xxx":123})
  7. print(obj)

总结:如果遇到obj["xxx"] = xx  , 

  1. - 重写了__setitem__方法
    - 继承dict

3、测试__name__方法

示例:

  1. app1中:
  2. import app2
  3. print('app1', __name__)
  4.  
  5. app2中:
  6. print('app2', __name__)

现在app1是主程序,运行结果截图

总结:如果是在自己的模块中运行,__name__就是__main__,如果是从别的文件中导入进来的,就不是__name__了

4、设置配置文件的几种方法

  1. ==========方式一:============
  2. app.config['SESSION_COOKIE_NAME'] = 'session_lvning' #这种方式要把所有的配置都放在一个文件夹里面,看起来会比较乱,所以选择下面的方式
  3. ==========方式二:==============
  4. app.config.from_pyfile('settings.py') #找到配置文件路径,创建一个模块,打开文件,并获取所有的内容,再将配置文件中的所有值,都封装到上一步创建的配置文件模板中
  5.  
  6. print(app.config.get("CCC"))
  7. =========方式三:对象的方式============
  8. import os
  9. os.environ['FLAKS-SETTINGS'] = 'settings.py'
  10. app.config.from_envvar('FLAKS-SETTINGS')
  11.  
  12. ===============方式四(推荐):字符串的方式,方便操作,不用去改配置,直接改变字符串就行了 ==============
  13. app.config.from_object('settings.DevConfig')
  14.  
  15. ----------settings.DevConfig----------
  16. from app import app
  17. class BaseConfig(object):
  18. NNN = 123 #注意是大写
  19. SESSION_COOKIE_NAME = "session_sss"
  20.  
  21. class TestConfig(BaseConfig):
  22. DB = "127.0.0.1"
  23.  
  24. class DevConfig(BaseConfig):
  25. DB = "52.5.7.5"
  26.  
  27. class ProConfig(BaseConfig):
  28. DB = "55.4.22.4"

要想在视图函数中获取配置文件的值,都是通过app.config来拿。但是如果视图函数和Flask创建的对象app不在一个模块。就得

导入来拿。可以不用导入,。直接导入一个current_app,这个就是当前的app对象,用current_app.config就能查看到了当前app的所有的配置文件

  1. from flask import Flask,current_app
  1. @app.route('/index',methods=["GET","POST"])
  2. def index():
  3. print(current_app.config) #当前的app的所有配置
  4. session["xx"] = "fdvbn"
  5. return "index"

一、数据库连接池

1、flask中是没有ORM的,如果在flask里面连接数据库有两种方式

1)pymysql:自己手动连接数据库用原始的sql语句

2)SQLAlchemy:SQLAlchemy 是python 操作数据库的一个库。能够进行 orm 映射官方文档 sqlchemy SQLAlchemy“采用简单的Python语言,为高效和高性能的数据库访问设计,实现了完整的企业级持久模型”。SQLAlchemy的理念是,SQL数据库的量级和性能重要于对象集合;而对象集合的抽象又重要于表和行。(和django的ORM类似)

2、链接池原理

  1. - BDUtils数据库链接池
  2. - 模式一:基于threaing.local实现为每一个线程创建一个连接,关闭是
  3. 伪关闭,当前线程可以重复
  4. - 模式二:连接池原理
  5. - 可以设置连接池中最大连接数 9
  6. - 默认启动时,连接池中创建连接 5
  7.  
  8. - 如果有三个线程来数据库中获取连接:
  9. - 如果三个同时来的,一人给一个链接
  10. - 如果一个一个来,有时间间隔,用一个链接就可以为三个线程提供服务
  11. - 说不准
  12. 有可能:1个链接就可以为三个线程提供服务
  13. 有可能:2个链接就可以为三个线程提供服务
  14. 有可能:3个链接就可以为三个线程提供服务
  15. PS、:maxshared在使用pymysql中均无用。链接数据库的模块:只有threadsafety>1的时候才有用

2、使用pymysql

为什么要使用数据库连接池呢?不用连接池有什么不好的地方呢?

1)每次操作都要链接数据库,链接次数过多

  1. #!usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import pymysql
  4. from flask import Flask
  5.  
  6. app = Flask(__name__)
  7.  
  8. # 方式一:这种方式每次请求,反复创建数据库链接,多次链接数据库会非常耗时
  9. # 解决办法:放在全局,单例模式
  10. @app.route('/index')
  11. def index():
  12. # 链接数据库
  13. conn = pymysql.connect(host="127.0.0.1",port=3306,user='root',password='', database='pooldb',charset='utf8')
  14. cursor = conn.cursor()
  15. cursor.execute("select * from td where id=%s", [5, ])
  16. result = cursor.fetchall() # 获取数据
  17. cursor.close()
  18. conn.close() # 关闭链接
  19. print(result)
  20. return "执行成功"
  21.  
  22. if __name__ == '__main__':
  23. app.run(debug=True)

2)不支持并发

  1. import pymysql
  2. from flask import Flask
  3. from threading import RLock
  4.  
  5. app = Flask(__name__)
  6. CONN = pymysql.connect(host="127.0.0.1",port=3306,user='root',password='', database='pooldb',charset='utf8')
  7. # 方式二:放在全局,如果是单线程,这样就可以,但是如果是多线程,就得加把锁。这样就成串行的了
  8. # 不支持并发,也不好。所有我们选择用数据库连接池
  9. @app.route('/index')
  10. def index():
  11. with RLock:
  12. cursor = CONN.cursor()
  13. cursor.execute("select * from td where id=%s", [5, ])
  14. result = cursor.fetchall() # 获取数据
  15. cursor.close()
  16. print(result)
  17. return "执行成功"
  18. if __name__ == '__main__':
  19. app.run(debug=True)

3、使用连接池

由于上面两种方案都不完美,所以得把方式一和方式二联合一下(既让减少链接次数,也能支持并发)

导入一个DButils模块

基于DButils实现的数据库连接池有两种模式

1)为每一个线程创建一个链接(是基于本地线程来实现的。thread.local),每个线程独立使用自己的数据库链接,该线程关闭不是真正的关闭,本线程再次调用时,还是使用的最开始创建的链接,直到线程终止,数据库链接才关闭

  1. #!usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. from flask import Flask
  4. app = Flask(__name__)
  5. from DBUtils.PersistentDB import PersistentDB
  6. import pymysql
  7. POOL = PersistentDB(
  8. creator=pymysql, # 使用链接数据库的模块
  9. maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
  10. setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
  11. ping=0,
  12. # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
  13. closeable=False,
  14. # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
  15. threadlocal=None, # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置
  16. host='127.0.0.1',
  17. port=3306,
  18. user='root',
  19. password='',
  20. database='pooldb',
  21. charset='utf8'
  22. )
  23.  
  24. @app.route('/func')
  25. def func():
  26.   conn = POOL.connection()
  27.   cursor = conn.cursor()
  28.   cursor.execute('select * from tb1')
  29.   result = cursor.fetchall()
  30.   cursor.close()
  31.   conn.close() # 不是真的关闭,而是假的关闭。 conn = pymysql.connect() conn.close()
  32.  
  33.   conn = POOL.connection()
  34.   cursor = conn.cursor()
  35.   cursor.execute('select * from tb1')
  36.   result = cursor.fetchall()
  37.   cursor.close()
  38.   conn.close()
  39. if __name__ == '__main__': app.run(debug=True)

注:如果线程比较多还是会创建很多连接

2)创建一个链接池,为所有线程提供连接,使用时来进行获取,使用完毕后在放回到连接池。

PS:假设最大链接数有10个,其实也就是一个列表,当你pop一个,人家会在append一个,链接池的所有的链接都是按照排队的这样的方式来链接的。链接池里所有的链接都能重复使用,共享的, 即实现了并发,又防止了链接次数太多

  1. import time
  2. import pymysql
  3. import threading
  4. from DBUtils.PooledDB import PooledDB, SharedDBConnection
  5. POOL = PooledDB(
  6. creator=pymysql, # 使用链接数据库的模块
  7. maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数
  8. mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
  9.  
  10. maxcached=5, # 链接池中最多闲置的链接,0和None不限制
  11. maxshared=3, # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
  12. blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
  13. maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
  14. setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
  15. ping=0,
  16. # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
  17. host='127.0.0.1',
  18. port=3306,
  19. user='root',
  20. password='',
  21. database='pooldb',
  22. charset='utf8'
  23. )
  24.  
  25. def func():
  26. # 检测当前正在运行连接数的是否小于最大链接数,如果不小于则:等待或报raise TooManyConnections异常
  27. # 否则
  28. # 则优先去初始化时创建的链接中获取链接 SteadyDBConnection。
  29. # 然后将SteadyDBConnection对象封装到PooledDedicatedDBConnection中并返回。
  30. # 如果最开始创建的链接没有链接,则去创建一个SteadyDBConnection对象,再封装到PooledDedicatedDBConnection中并返回。
  31. # 一旦关闭链接后,连接就返回到连接池让后续线程继续使用。
  32.  
  33. # PooledDedicatedDBConnection
  34. conn = POOL.connection()
  35.  
  36. # print(th, '链接被拿走了', conn1._con)
  37. # print(th, '池子里目前有', pool._idle_cache, '\r\n')
  38.  
  39. cursor = conn.cursor()
  40. cursor.execute('select * from tb1')
  41. result = cursor.fetchall()
  42. conn.close()
  43.  
  44. conn = POOL.connection()
  45.  
  46. # print(th, '链接被拿走了', conn1._con)
  47. # print(th, '池子里目前有', pool._idle_cache, '\r\n')
  48.  
  49. cursor = conn.cursor()
  50. cursor.execute('select * from tb1')
  51. result = cursor.fetchall()
  52. conn.close()
  53.  
  54. func()

二、本地线程

1、没用线程之前 

  1. import threading
  2. import time
  3. class Foo(object):
  4. def __init__(self):
  5. self.name = None
  6. local_values = Foo()
  7.  
  8. def func(num):
  9. time.sleep(2)
  10. local_values.name = num
  11. print(local_values.name,threading.current_thread().name)
  12.  
  13. for i in range(5):
  14. th = threading.Thread(target=func, args=(i,), name='线程%s' % i)
  15. th.start()

打印结果:

  1. 1 线程1
  2. 0 线程0
  3. 2 线程2
  4. 3 线程3
  5. 4 线程4

2、用了本地线程之后

  1. import threading
  2. import time
  3. # 本地线程对象
  4. local_values = threading.local()
  5. def func(num):
  6.  
  7. """
  8. # 第一个线程进来,本地线程对象会为他创建一个
  9. # 第二个线程进来,本地线程对象会为他创建一个
  10. {
  11. 线程1的唯一标识:{name:1},
  12. 线程2的唯一标识:{name:2},
  13. }
  14. :param num:
  15. :return:
  16. """
  17. local_values.name = num #
  18. # 线程停下来了
  19. time.sleep(2)
  20. # 第二个线程: local_values.name,去local_values中根据自己的唯一标识作为key,获取value中name对应的值
  21. print(local_values.name, threading.current_thread().name)
  22.  
  23. for i in range(5):
  24. th = threading.Thread(target=func, args=(i,), name='线程%s' % i)
  25. th.start()

打印结果:

  1. 1 线程1
  2. 2 线程2
  3. 0 线程0
  4. 4 线程4
  5. 3 线程3

三、上下文管理

 1、上下文概述

  1. a、类似于本地线程
  2. 创建Local类:
  3. {
  4. 线程或协程唯一标识: { 'stack':[request],'xxx':[session,] },
  5. 线程或协程唯一标识: { 'stack':[] },
  6. 线程或协程唯一标识: { 'stack':[] },
  7. 线程或协程唯一标识: { 'stack':[] },
  8. }
  9. b、上下文管理的本质
  10. 每一个线程都会创建一个上面那样的结构,
  11. 当请求进来之后,将请求相关数据添加到列表里面[request,],以后如果使用时,就去读取
  12. 列表中的数据,请求完成之后,将request从列表中移除
  13. c、关系
  14. local = 小华={
  15. 线程或协程唯一标识: { 'stack':[] },
  16. 线程或协程唯一标识: { 'stack':[] },
  17. 线程或协程唯一标识: { 'stack':[] },
  18. 线程或协程唯一标识: { 'stack':[] },
  19. }
  20. stack = 强哥 = {
  21. push
  22. pop
  23. top
  24. }
  25. 存取东西时都要基于强哥来做
  26. d、最近看过一些flask源码,flask还是django有些区别
  27. - FlaskDjango区别?
  28. - 请求相关数据传递的方式
  29. - django:是通过传request参数实现的
  30. - Flask:基于local对象和,localstark对象来完成的
  31. 当请求刚进来的时候就给放进来了,完了top取值就行了,取完之后pop走就行了
  32.  
  33. 问题:多个请求过来会不会混淆
  34. -答: 不会,因为,不仅是线程的,还是协程,每一个协程都是有唯一标识的:
  35. from greenlent import getcurrentt as get_ident #这个就是来获取唯一标识的

2、flask的request和session设置方式比较新颖,如果没有这种方式,那么就只能通过参数的传递。

flask是如何做的呢?

  1. - 本地线程:
  2. Flask自己创建的一个线程(猜想:内部是不是基于本地线程做的?)
  3. vals = threading.local()
  4. def task(arg):
  5. vals.name = num
  6. - 每个线程进来都是打印的自己的,只有自己的才能修改,
  7. - 通过他就能保证每一个线程里面有一个数据库链接,通过他就能创建出数据库链接池的第一种模式
  8. - 上下文原理
  9. - 类似于本地线程
  10. - 猜想
  11. 内部是不是基于本地线程做的?不是,是一个特殊的字典
  1. from functools import partial
  2. from flask.globals import LocalStack, LocalProxy
  3.  
  4. ls = LocalStack()
  5.  
  6. class RequestContext(object):
  7. def __init__(self, environ):
  8. self.request = environ
  9.  
  10. def _lookup_req_object(name):
  11. top = ls.top
  12. if top is None:
  13. raise RuntimeError(ls)
  14. return getattr(top, name)
  15.  
  16. session = LocalProxy(partial(_lookup_req_object, 'request'))
  17.  
  18. ls.push(RequestContext('c1')) # 当请求进来时,放入
  19. print(session) # 视图函数使用
  20. print(session) # 视图函数使用
  21. ls.pop() # 请求结束pop
  22.  
  23. ls.push(RequestContext('c2'))
  24. print(session)
  25.  
  26. ls.push(RequestContext('c3'))
  27. print(session)

3、Flask内部实现

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3.  
  4. from greenlet import getcurrent as get_ident
  5.  
  6. def release_local(local):
  7. local.__release_local__()
  8.  
  9. class Local(object):
  10. __slots__ = ('__storage__', '__ident_func__')
  11.  
  12. def __init__(self):
  13. # self.__storage__ = {}
  14. # self.__ident_func__ = get_ident
  15. object.__setattr__(self, '__storage__', {})
  16. object.__setattr__(self, '__ident_func__', get_ident)
  17.  
  18. def __release_local__(self):
  19. self.__storage__.pop(self.__ident_func__(), None)
  20.  
  21. def __getattr__(self, name):
  22. try:
  23. return self.__storage__[self.__ident_func__()][name]
  24. except KeyError:
  25. raise AttributeError(name)
  26.  
  27. def __setattr__(self, name, value):
  28. ident = self.__ident_func__()
  29. storage = self.__storage__
  30. try:
  31. storage[ident][name] = value
  32. except KeyError:
  33. storage[ident] = {name: value}
  34.  
  35. def __delattr__(self, name):
  36. try:
  37. del self.__storage__[self.__ident_func__()][name]
  38. except KeyError:
  39. raise AttributeError(name)
  40.  
  41. class LocalStack(object):
  42. def __init__(self):
  43. self._local = Local()
  44.  
  45. def __release_local__(self):
  46. self._local.__release_local__()
  47.  
  48. def push(self, obj):
  49. """Pushes a new item to the stack"""
  50. rv = getattr(self._local, 'stack', None)
  51. if rv is None:
  52. self._local.stack = rv = []
  53. rv.append(obj)
  54. return rv
  55.  
  56. def pop(self):
  57. """Removes the topmost item from the stack, will return the
  58. old value or `None` if the stack was already empty.
  59. """
  60. stack = getattr(self._local, 'stack', None)
  61. if stack is None:
  62. return None
  63. elif len(stack) == 1:
  64. release_local(self._local)
  65. return stack[-1]
  66. else:
  67. return stack.pop()
  68.  
  69. @property
  70. def top(self):
  71. """The topmost item on the stack. If the stack is empty,
  72. `None` is returned.
  73. """
  74. try:
  75. return self._local.stack[-1]
  76. except (AttributeError, IndexError):
  77. return None
  78.  
  79. stc = LocalStack()
  80.  
  81. stc.push(123)
  82. v = stc.pop()
  83.  
  84. print(v)

flask之基于DBUtils实现数据库连接池、本地线程、上下文的更多相关文章

  1. 3、flask之基于DBUtils实现数据库连接池、本地线程、上下文

    本篇导航: 数据库连接池 本地线程 上下文管理 面向对象部分知识点解析 1.子类继承父类__init__的三种方式 class Dog(Animal): #子类 派生类 def __init__(se ...

  2. Flask【第3篇】:蓝图、基于DBUtils实现数据库连接池、上下文管理等

    基于DBUtils实现数据库连接池 小知识: 1.子类继承父类的三种方式 class Dog(Animal): #子类 派生类 def __init__(self,name,breed, life_v ...

  3. 蓝图、基于DBUtils实现数据库连接池、上下文管理等

    基于DBUtils实现数据库连接池 小知识: 1.子类继承父类的三种方式 class Dog(Animal): #子类 派生类 def __init__(self,name,breed, life_v ...

  4. Flask学习【第3篇】:蓝图、基于DBUtils实现数据库连接池、上下文管理等

    小知识 子类继承父类的三种方式 class Dog(Animal): #子类 派生类 def __init__(self,name,breed, life_value,aggr): # Animal. ...

  5. Flask系列(三)蓝图、基于DButils实现数据库连接池、上下文管理

    知识点回顾 1.子类继承父类的三种方式 class Dog(Animal): #子类 派生类 def __init__(self,name,breed, life_value,aggr): # Ani ...

  6. 基于DBUtils实现数据库连接池及flask项目部署

    阅读目录 flask中是没有ORM的,如果在flask里面连接数据库有两种方式 数据库连接池原理 模式一: 模式二: 数据库连接池 flask中是没有ORM的,如果在flask里面连接数据库有两种方式 ...

  7. 基于DBUtils实现数据库连接池

    小知识: 1.子类继承父类的三种方式 class Dog(Animal): #子类 派生类 def __init__(self,name,breed, life_value,aggr): # Anim ...

  8. paip.提升性能----数据库连接池以及线程池以及对象池

    paip.提升性能----数据库连接池以及线程池以及对象池 目录:数据库连接池c3po,线程池ExecutorService:Jakartacommons-pool对象池 作者Attilax  艾龙, ...

  9. 基于JDBC的数据库连接池技术研究与应用

    引言 近年来,随着Internet/Intranet建网技术的飞速发展和在世界范围内的迅速普及,计算机 应用程序已从传统的桌面应用转到Web应用.基于B/S(Browser/Server)架构的3层开 ...

随机推荐

  1. .net core2.1 - ef core数据库迁移,初始化种子数据

    起因:早上偶然看见一篇文章说是ef core(2.x)使用种子数据,主表子表迁移时候,正常情况下说是无法迁移成功,索性就试试,结果是和ef6的一样,没感觉有什么大的区别.一切OK,见下面内容. 1.首 ...

  2. Linux 记录所有用户登录和操作的详细日志

    1.起因 最近Linux服务器上一些文件呗篡改,想追查已经查不到记录了,所以得想个办法记录下所有用户的操作记录. 一般大家通常会采用history来记录,但是history有个缺陷就是默认是1000行 ...

  3. JDK5的新特性之增强for循环遍历数组或集合

    [格式] for(元素的类型 变量名 : 数组或Collection集合名){ //此处使用变量名即可,该变量就是普通for里的i. }

  4. thinkphp验证器

    验证器类:$validate=new \think\Validate($rule,$message,$field); 独立验证: //独立验证 $rule=[ 'name' => 'requir ...

  5. Team Queue POJ - 2259 (队列)

    Queues and Priority Queues are data structures which are known to most computer scientists. The Team ...

  6. Codeforces 1130D1 Toy Train (Simplified) (思维)【贪心】

    <题目链接> 题目大意: 有一个的环形火车站,其中有$[1,n] n$个站台,站台上能够放糖果,火车只能朝一个方向移动,如果火车在站台$i$,那么下一秒就会在$i+1$站(如果$i=n$, ...

  7. 常见素数筛选方法原理和Python实现

    1. 普通筛选(常用于求解单个素数问题) 自然数中,除了1和它本身以外不再有其他因数. import math def func_get_prime(n): func = lambda x: not ...

  8. spring_AOP_XML

    例子下载 对于xml的AOP配置主要集中在配置文件中,所以只要设置好配置文件就行了 beans.xml <?xml version="1.0" encoding=" ...

  9. Django 学习第三天——模板变量及模板过滤器

    一.模板路径的查找: 查找顺序:(现在哪找到就用那个) 首先在主目录的 setting.py 文件里的 TEMPLATES 中的 DIRS 里找: 其次如果 DIRS 中的 APP_DIRS : 'T ...

  10. spring boot整合servlet、filter、Listener等组件方式

    创建一个maven项目,然后此项目继承一个父项目:org.springframework.boot 1.创建一个maven项目: 2.点击next后配置父项目及版本号 3.点击finish后就可查看p ...