插图:恶搞图15
在后端开发中免不掉与数据库打交道,无非是使用orm
或者原生sql
来操作数据库。
在python中通过原生sql操作数据库,主流就两种。
- 使用pymysql模块:
pymysql
支持python2.x
和python3.x
的版本
- 使用mysqldb模块:
mysqldb
仅支持python2.x
的版本
orm的使用以flask和django为例。
- flask使用的orm是基于
SQLAlchemy
(SQLAlchemy本就是orm),flask团队并在SQLAlchemy
基础之上又封装了一个Flask-SQLchemy
并予以应用 。
- django使用的orm是django自带的orm。
orm的操作数据库的方式我们已经熟知了,这里我们聊一聊如何在web中使用原生sql操作数据库,以及会出现的问题。
把所有的数据库操作全部都放在了视图函数里面。
| from flask import Flask |
| |
| app = Flask(__name__) |
| |
| @app.route("/") |
| def hello(): |
| import pymysql |
| CONN = pymysql.connect(host='127.0.0.1', |
| port=3306, |
| user='root', |
| password='123', |
| database='pooldb', |
| charset='utf8') |
| |
| cursor = CONN.cursor() |
| cursor.execute('select * from tb1') |
| result = cursor.fetchall() |
| cursor.close() |
| |
| print(result) |
| |
| return "Hello World" |
| |
| if __name__ == '__main__': |
| app.run() |
会出现的问题
- 很多个用户并发的来请求,一个用户可以理解为一个线程,每个线程都会跟数据库建立连接,数据库承受不了这种量级的连接数。
为了避免之前每个用户都建立连接,我们把数据库连接放到了全局变量里面,只会建立一次连接,但是依然会出现问题。
| from flask import Flask |
| |
| app = Flask(__name__) |
| import pymysql |
| CONN = pymysql.connect(host='127.0.0.1', |
| port=3306, |
| user='root', |
| password='123', |
| database='pooldb', |
| charset='utf8') |
| |
| @app.route("/") |
| def hello(): |
| cursor = CONN.cursor() |
| cursor.execute('select * from tb1') |
| result = cursor.fetchall() |
| cursor.close() |
| |
| print(result) |
| |
| return "Hello World" |
| |
| if __name__ == '__main__': |
| app.run() |
会出现的问题:
- 会出现线程安全问题,比如如果第一个用户拿到了连接给关闭了,而第二个用户正在进行查询,第二个用户查询的时候第一个用户把连接断了,会导致第二个用户出现问题。
- 假设第一用户查询了一下表1,正准备获取查询的内容,这时第二个人查询了一下表2,由于cursor对象都是同一个,第一个人获取到的查询内容就是表2的内容了,所以也会出现线程安全问题
为了避免之前的线程不安全,在示例2的基础上加上一把线程锁
| from flask import Flask |
| import threading |
| app = Flask(__name__) |
| import pymysql |
| CONN = pymysql.connect(host='127.0.0.1', |
| port=3306, |
| user='root', |
| password='123', |
| database='pooldb', |
| charset='utf8') |
| |
| @app.route("/") |
| def hello(): |
| with threading.Lock(): |
| cursor = CONN.cursor() |
| cursor.execute('select * from tb1') |
| result = cursor.fetchall() |
| cursor.close() |
| |
| print(result) |
| |
| return "Hello World" |
| |
| if __name__ == '__main__': |
| app.run() |
会出现的问题: