本篇导航:

面向对象部分知识点解析

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)

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

  1. 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. Mezzanine (Windows10下)安装配置与修改(更新中)

    最近自己搭个系统,发现Mezzanine很快,先搞个python 2.7, pip. 然后两个方法: 1. $ pip install mezzanine 2. Git下载,解压 后进入目录,创建项目 ...

  2. 再叙ASM

    上一篇文章,我们已体验到ASM的威力,那么结合上面的代码解释ASM是怎么执行的. ClassWriter clazzWriter = new ClassWriter(0); 首先看下官方文档对Clas ...

  3. 2018年web前端学习路线图

    前端的的技术一直在变化,更新和变革,现在基本是三驾马车(vue,angualr,react)主导整个前端框架,但是无论对于新人或者有经验的程序员,这些知识在必须掌握 前端必会技能 上图罗列了整个前端的 ...

  4. python_如何读写csv数据

    案例: 通过股票网站,我们获取了中国股市数据集,它以csv数据格式存储 Data,Open,High,Low,Close,Volume,Adj Close 2016-06-28,8.63,8.47,8 ...

  5. python_如何对迭代器进行切片操作

    案例: 对于某个文件,我只想读取到其中100~200行之间的内容,是否可以通过切片的方式进行读取? 我想: f = open() f[100:200] 可行? 如何解决这个问题? 方法1: 全部读取到 ...

  6. word中正文分栏重新换页问题

    小论文常需要正文分栏,但是标题.摘要不分栏的编排格式. 1.在摘要后面加入分隔符来将内容分为摘要和正文两个部分.选择 插入→分隔符→分节符(连续). 2.然后进行分栏.选择 格式→分栏. 3.此时如果 ...

  7. 04_Javascript初步第一天

    视频来源:麦子学院[看来是麦子的忠实粉丝] 讲师:King我只是想记住对应的中文翻译:Uncaught SyntaxError: missing ) after argument list//属性列表 ...

  8. Angular之ngRoute与uiRoute

    ngRoute不支持嵌套路由 用法如下: <!DOCTYPE html> <html lang="en" ng-app="myApp"> ...

  9. TOMCAT原理详解及请求过程

    Tomcat: Tomcat是一个JSP/Servlet容器.其作为Servlet容器,有三种工作模式:独立的Servlet容器.进程内的Servlet容器和进程外的Servlet容器. Tomcat ...

  10. CentOS 7修改网卡名称

    CentOS 7 修改网卡名为eth0 标签: linux 笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 CentOS7的网卡名称太长,这不符合我们的使用习惯, ...