数据备份与pymysql模块

阅读目录

一、IDE工具(Navicat)介绍

生产环境还是推荐使用mysql命令行,但为了方便我们测试,可以使用IDE工具

下载链接:

链接:https://pan.baidu.com/s/13JmtWAyO2-36SJjsm4tb6Q
提取码:qcgg

掌握:
#1. 测试+链接数据库
#2. 新建库
#3. 新建表,新增字段+类型+约束
#4. 设计表:外键
#5. 新建查询
#6. 备份库/表

#注意:
批量加注释:ctrl+?键
批量去注释:ctrl+?键,ps:有的版本是ctrl+shift+?

二、MySQL数据备份

#1. 物理备份: 直接复制数据库文件,适用于大型数据库环境。但不能恢复到异构系统中如Windows。
#2. 逻辑备份: 备份的是建表、建库、插入等操作所执行SQL语句,适用于中小型数据库,效率相对较低。
#3. 导出表: 将表导入到文本文件中。

使用mysqldump实现逻辑备份

#语法:
# mysqldump -h 服务器 -u用户名 -p密码 数据库名 > 备份文件.sql

#示例:
#单库备份
mysqldump -uroot -p123 db1 > db1.sql
mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql

#多库备份
mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql

#备份所有库
mysqldump -uroot -p123 --all-databases > all.sql 

示例:(在windows上执行备份命令)

管理员身份进入cmd,进入到MySQL的安装目录下的bin目录,执行下图命令之后,就会在bin目录下生成备份文件alldb.sql

 

 注意:在命令行输入命令时,别在-p后跟密码,提示输入密码后手动输入,如果在命令行-p跟密码,有可能会报错如下:

 

恢复逻辑备份

#方法一:这个命令在linux执行正常
[root@egon backup]# mysql -uroot -p123 < /backup/all.sql
注意:
在windows上要先创建即将要备份的数据库,然后再恢复,恢复命令也要指定导入到创建的数据库
#mysql -uroot -p123 之前创建的数据库名 < /backup/all.sql
#方法二:进入mysql命令行 mysql> source /backup/all.sql

示例:在windows执行恢复备份

先进入mysql命令行,

注意,要先创建要导入的数据库,例如本次要导入的数据库名为userinfo_db

mysql> create database userinfo_db;
Query OK, 1 row affected (0.00 sec)

mysql> use userinfo_db;
Database changed

mysql> source D:\mysql5.6\mysql-5.6.37-winx64\bin\alldb.sql  #再执行source命令恢复

mysql> show tables;
+-----------------------+
| Tables_in_userinfo_db |
+-----------------------+
| baseinfo              |
| class                 |
| cmd                   |
| emp                   |
| errlog                |
| studnet               |
| user                  |
+-----------------------+
7 rows in set (0.00 sec)

mysql>

备份/恢复案例

#数据库备份/恢复实验一:数据库损坏
备份:
1. # mysqldump -uroot -p123 --all-databases > /backup/`date +%F`_all.sql
2. # mysql -uroot -p123 -e 'flush logs' //截断并产生新的binlog
3. 插入数据 //模拟服务器正常运行
4. mysql> set sql_log_bin=0; //模拟服务器损坏
mysql> drop database db;

恢复:
1. # mysqlbinlog 最后一个binlog > /backup/last_bin.log
2. mysql> set sql_log_bin=0; 
mysql> source /backup/2014-02-13_all.sql //恢复最近一次完全备份 
mysql> source /backup/last_bin.log //恢复最后个binlog文件


#数据库备份/恢复实验二:如果有误删除
备份:
1. mysqldump -uroot -p123 --all-databases > /backup/`date +%F`_all.sql
2. mysql -uroot -p123 -e 'flush logs' //截断并产生新的binlog
3. 插入数据 //模拟服务器正常运行
4. drop table db1.t1 //模拟误删除
5. 插入数据 //模拟服务器正常运行

恢复:
1. # mysqlbinlog 最后一个binlog --stop-position=260 > /tmp/1.sql 
# mysqlbinlog 最后一个binlog --start-position=900 > /tmp/2.sql 
2. mysql> set sql_log_bin=0; 
mysql> source /backup/2014-02-13_all.sql //恢复最近一次完全备份
mysql> source /tmp/1.log //恢复最后个binlog文件
mysql> source /tmp/2.log //恢复最后个binlog文件

注意事项:
1. 完全恢复到一个干净的环境(例如新的数据库或删除原有的数据库)
2. 恢复期间所有SQL语句不应该记录到binlog中

实现自动化备份

备份计划:
1. 什么时间 2:00
2. 对哪些数据库备份
3. 备份文件放的位置

备份脚本:
[root@egon ~]# vim /mysql_back.sql
#!/bin/bash
back_dir=/backup
back_file=`date +%F`_all.sql
user=root
pass=123

if [ ! -d /backup ];then
mkdir -p /backup
fi

# 备份并截断日志
mysqldump -u${user} -p${pass} --events --all-databases > ${back_dir}/${back_file}
mysql -u${user} -p${pass} -e 'flush logs'

# 只保留最近一周的备份
cd $back_dir
find . -mtime +7 -exec rm -rf {} \;

手动测试:
[root@egon ~]# chmod a+x /mysql_back.sql 
[root@egon ~]# chattr +i /mysql_back.sql
[root@egon ~]# /mysql_back.sql

配置cron:
[root@egon ~]# crontab -l
2 * * * /mysql_back.sql

表的导出和导入

SELECT... INTO OUTFILE 导出文本文件
示例:
mysql> SELECT * FROM school.student1
INTO OUTFILE 'student1.txt'
FIELDS TERMINATED BY ',' //定义字段分隔符
OPTIONALLY ENCLOSED BY '' //定义字符串使用什么符号括起来
LINES TERMINATED BY '\n' ; //定义换行符


mysql 命令导出文本文件
示例:
# mysql -u root -p123 -e 'select * from student1.school' > /tmp/student1.txt
# mysql -u root -p123 --xml -e 'select * from student1.school' > /tmp/student1.xml
# mysql -u root -p123 --html -e 'select * from student1.school' > /tmp/student1.html

LOAD DATA INFILE 导入文本文件
mysql> DELETE FROM student1;
mysql> LOAD DATA INFILE '/tmp/student1.txt'
INTO TABLE school.student1
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY ''
LINES TERMINATED BY '\n';
#可能会报错
mysql> select * from db1.emp into outfile 'C:\\db1.emp.txt' fields terminated by ',' lines terminated by '\r\n';
ERROR 1238 (HY000): Variable 'secure_file_priv' is a read only variable


#数据库最关键的是数据,一旦数据库权限泄露,那么通过上述语句就可以轻松将数据导出到文件中然后下载拿走,因而mysql对此作了限制,只能将文件导出到指定目录
在配置文件中
[mysqld]
secure_file_priv='C:\\' #只能将数据导出到C:\\下

重启mysql
重新执行上述语句

数据库迁移

务必保证在相同版本之间迁移
# mysqldump -h 源IP -uroot -p123 --databases db1 | mysql -h 目标IP -uroot -p456

三、pymysql模块

#安装(管理员运行cmd)
pip3 install pymysql

3.1 链接、执行sql、关闭(游标)

import pymysql

# 链接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    database='atm_db',
    charset='utf8',
    # autocommit=True    # 自动提交,可以不加
)
# 生成游标对象
cursor = conn.cursor()  # 执行完毕返回的结果集默认以元组显示
# cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)   #执行完毕返回的结果集以字典显示

user=input('用户名: ').strip()
pwd=input('密码: ').strip()

# 执行sql语句
sql = 'select * from userinfo where username=%s and password=%s'
val=(user, pwd)  
res = cursor.execute(sql,val)  # 执行sql语句,返回sql查询成功的记录数目
#也可以写成
#res = cursor.execute(sql,(user, pwd))
print(res)

cursor.close()
conn.close()

if res:
    print('登录成功')
else:
    print('登录失败')

3.2 execute()之sql注入

注意:符号--会注释掉它之后的sql,正确的语法:--后至少有一个任意字符

根本原理:就根据程序的sql语句字符串拼接中name='%s',我们输入一个xxx' -- haha,用我们输入的xxx加'在程序中拼接成一个判断条件name='xxx' -- haha'

#示例:
sql = 'select * from userinfo where username="%s" and password="%s"'  %(user,pwd)
res = cursor.execute(sql)  

#ps:有个注意的地方,就是sql语句拼接中%s如果用的双引号,那么我们输入xxx加"
#总之,看你的sql语句中%s用的什么引号,输的时候就跟什么

#不同注入方法
#1、sql注入之:用户存在,绕过密码
egon' -- 任意字符

#2、sql注入之:用户不存在,绕过用户与密码
xxx' or 1=1 -- 任意字符

示例(程序代码)

import pymysql

# 链接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    database='atm_db',
    charset='utf8'
)
# 游标
cursor = conn.cursor()  # 执行完毕返回的结果集默认以元组显示
# cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)   #执行完毕返回的结果集以字典显示

user=input('用户名: ').strip()
pwd=input('密码: ').strip()

# 执行sql语句
sql = 'select * from userinfo where username="%s" and password="%s"'  %(user,pwd)
print("sql语句",sql)
res = cursor.execute(sql)  # 执行sql语句,返回sql查询成功的记录数目
print(res)

cursor.close()
conn.close()

if res:
    print('登录成功')
else:
    print('登录失败')

不同输入效果(注意代码中sql语句用的是双引号)

用户存在绕过密码:

 用户不存在:

 解决方法:

# 原来代码中是对对sql进行字符串拼接
sql = 'select * from userinfo where username="%s" and password="%s"'  %(user,pwd)
print("sql语句",sql)
res = cursor.execute(sql) 

#改写为(execute帮我们做字符串拼接,我们无需且一定不能再为%s加引号也无需在sql后%(user,pwd)去指定,在)
sql="select * from userinfo where name=%s and password=%s" #注意%s需要去掉引号,因为execute方法会自动为我们加上
res=cursor.execute(sql,[user,pwd]) # execute自动识别sql里面的%s用后面元组里面的数据替换

修改过后的代码:

import pymysql

# 链接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    database='atm_db',
    charset='utf8'
)
# 游标
cursor = conn.cursor()  # 执行完毕返回的结果集默认以元组显示
# cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)   #执行完毕返回的结果集以字典显示

user=input('用户名: ').strip()
pwd=input('密码: ').strip()

# 执行sql语句
sql = 'select * from userinfo where username=%s and password=%s'
val=(user, pwd)  
res = cursor.execute(sql,val)  # 执行sql语句,返回sql查询成功的记录数目
#也可以写成
#res = cursor.execute(sql,(user, pwd))
print(res)

cursor.close()
conn.close()

if res:
    print('登录成功')
else:
    print('登录失败')

3.3 增、删、改:conn.commit()

import pymysql

# 链接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    database='school',
    charset='utf8',
    # autocommit=True    # 自动提交,可以不加
)
# 生成游标对象
# cursor = conn.cursor()  # 执行完毕返回的结果集默认以元组显示
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)  # 执行完毕返回的结果集以字典显示

# 增加
"""
#part1(插入单条记录)
# sql='insert into userinfo(username,password) values("root","123456");'
# res=cursor.execute(sql) #执行sql语句,返回sql影响成功的行数
# print(res)

#part2(插入单条记录)
#sql='insert into userinfo(username,password) values(%s,%s);'
#res=cursor.execute(sql,("root","123456")) #执行sql语句,返回sql影响成功的行数
#print(res)
#ps:
'''
add_name="root
passwd="123456"
sql='insert into userinfo(username,password) values(%s,%s);'
val=(add_name,passwd)
res=cursor.execute(sql,val)    #可以将元组提出了在外面通过变量给元组赋值
'''

#part3(插入多条记录)
sql='insert into userinfo(name,password) values(%s,%s);'
res=cursor.executemany(sql,[("root","123456"),("lhf","12356"),("eee","156")]) #执行sql语句,返回sql影响成功的行数
print(res)

conn.commit() #提交后插入记录才能成功
cursor.close()
conn.close()
"""

# =================修改====================
# sql = "update userinfo set username=%s where username=%s"
# res = cursor.execute(sql, ["alias", "root"])
# print(res)
#
# conn.commit() # 提交后插入记录才能成功
# cursor.close()
# conn.close()
# ====================================


# ===============删除==================
sql = "delete from userinfo where username=%s"
res = cursor.execute(sql, ["alias"])
print(res)

conn.commit() # 提交后插入记录才能成功
cursor.close()
conn.close()
# ===================================

查:fetchone,fetchmany,fetchall

import pymysql
# 链接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    database='atm_db',
    charset='utf8'
)
# 游标
cursor = conn.cursor()  # 执行完毕返回的结果集默认以元组显示
# cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)   #执行完毕返回的结果集以字典显示


#执行sql语句
sql='select * from userinfo;'
rows=cursor.execute(sql) #执行sql语句,返回sql影响成功的行数rows,将结果放入一个队列,等待被查询

# cursor.scroll(3,mode='absolute') # 相对绝对位置移动,相对于返回结果队列队首移动3,括号内设置几就移动几,比如当前位置在结果队列的第五个结果,写了(2,mode="absolute"),那就是从结果起始位置移动2个结果开始 
# cursor.scroll(3,mode='relative') # 相对当前位置移动,相对于游标在返回结果队列当前所在位置
res1=cursor.fetchone()   #从命令返回的结果队列中当前位置取出一条记录
res2=cursor.fetchone()
res3=cursor.fetchone()
res4=cursor.fetchmany(2) #从命令返回的结果队列中当前位置取出2条记录,括号内设置几就取几条
res5=cursor.fetchall()      #从命令返回的结果队列中当前位置之后所有记录
print(res1)
print(res2)
print(res3)
print(res4)
print(res5)

cursor.close()
conn.close()

获取插入的最后一条数据的自增ID

import pymysql
# 链接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    database='atm_db',
    charset='utf8'
)
# 游标
cursor = conn.cursor()  # 执行完毕返回的结果集默认以元组显示
# cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)   #执行完毕返回的结果集以字典显示

sql='insert into userinfo(username,password) values(%s,%s);'
val=("jason","123456")
rows=cursor.execute(sql,val)
print(cursor.lastrowid) #在插入语句后查看

conn.commit()
cursor.close()
conn.close()

 3.4 pymysql 执行事务操作

import pymysql

# 链接
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    database='school',
    charset='utf8',
    # autocommit=True    # 自动提交,可以不加
)
# 游标
cursor = conn.cursor()  # 执行完毕返回的结果集默认以元组显示
# cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)   #执行完毕返回的结果集以字典显示

sql_1 = "update emp set age=11 where name='jason'"
sql_2 = "update emp set age=22 where name='egon'"
sql_3 = "dele from emp where id=100"

try:
    cursor.execute(sql_1)
    cursor.execute(sql_2)
    cursor.execute(sql_3) # 语法错误

except Exception as e:
    conn.rollback()  # 事务回滚
    print('事务处理失败', e)
else:
    conn.commit()  # 事务提交
    print('事务处理成功', cursor.rowcount)

# 关闭连接
cursor.close()
conn.close()

执行结果:

# 事务处理失败 (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'dele from emp where id=100' at line 1")

3.5 pymysql-普通的数据库连接

初级阶段

import pymysql
from flask import Flask

app = Flask(__name__)


def fetchall(sql):
    conn = pymysql.connect(host='127.0.0.1', user='root', password='123456', database='router_auth')
    # 游标
    cursor = conn.cursor()
    rows = cursor.execute(sql)
    result = cursor.fetchall()
    cursor.close()
    conn.close()

    return result


@app.route('/login')
def login():
    result = fetchall('select * from app01_user')
    print(result)
    return 'login'


@app.route('/index')
def index():
    result = fetchall('select * from app01_user')
    print(result)

    return 'index'


@app.route('/order')
def order():
    result = fetchall('select * from app01_user')
    print(result)

    return 'order'


if __name__ == '__main__':
    app.run()
普通的数据库连接

 修改版,全局共用一个conn

import pymysql
from flask import Flask

app = Flask(__name__)
CONN = pymysql.connect(host='127.0.0.1', user='root', password='123456', database='router_auth')


def fetchall(sql):
    # conn = pymysql.connect(host='127.0.0.1', user='root', password='123456', database='router_auth')
    # 游标
    cursor = CONN.cursor()
    rows = cursor.execute(sql)
    result = cursor.fetchall()
    cursor.close()
    # conn.close()

    return result


@app.route('/login')
def login():
    result = fetchall('select * from app01_user')
    print(result)
    return 'login'


@app.route('/index')
def index():
    result = fetchall('select * from app01_user')
    print(result)

    return 'index'


@app.route('/order')
def order():
    result = fetchall('select * from app01_user')
    print(result)

    return 'order'


if __name__ == '__main__':
    app.run()
修改版,使用同一个连接

3.6 数据库连接池

1)安装

# pip3 install dbutils
# pip3 install pymysql

版本:Successfully installed dbutils-3.0.2

2)使用

 DBUtils是Python的一个用于实现数据库连接池的模块。

#模块导入
# 注意这里PersistentDB是在persistent_db Module当中
from dbutils.persistent_db import PersistentDB
from dbutils.pooled_db import PooledDB, SharedDBConnection

此连接池有两种连接模式:

  • 模式一:为每个线程创建一个连接,线程即使调用了close方法,也不会关闭,只是把连接重新放到连接池,供自己线程再次使用。当线程终止时,连接自动关闭。
POOL = PersistentDB(
    creator=pymysql,  # 使用链接数据库的模块
    maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
    setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
    ping=0,
    # 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
    closeable=False,
    # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
    threadlocal=None,  # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123',
    database='pooldb',
    charset='utf8'
)

def func():
    conn = POOL.connection(shareable=False)
    cursor = conn.cursor()
    cursor.execute('select * from tb1')
    result = cursor.fetchall()
    cursor.close()
    conn.close()

func()
View Code
  • 模式二:创建一批连接到连接池,供所有线程共享使用。

         PS:由于pymysql、MySQLdb等threadsafety值为1,所以该模式连接池中的线程会被所有线程共享。

import pymysql
from dbutils.persistent_db import PersistentDB
from dbutils.pooled_db import PooledDB, SharedDBConnection
import threading
import time

# 连接池
POOL = PooledDB(
    creator=pymysql,  # 使用链接数据库的模块
    maxconnections=6,  # 连接池允许的最大连接数,0和None表示不限制连接数
    mincached=2,  # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
    maxcached=5,  # 链接池中最多闲置的链接,0和None不限制
    maxshared=3,
    # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
    blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
    maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
    setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
    ping=0,
    # 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
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    database='router_auth',
    charset='utf8'
)


def task(num):
    # 检测当前正在运行连接数的是否小于最大链接数,如果不小于则:等待或报raise TooManyConnections异常
    # 否则
    # 则优先去初始化时创建的链接中获取链接 SteadyDBConnection。
    # 然后将SteadyDBConnection对象封装到PooledDedicatedDBConnection中并返回。
    # 如果最开始创建的链接没有链接,则去创建一个SteadyDBConnection对象,再封装到PooledDedicatedDBConnection中并返回。
    # 一旦关闭链接后,连接就返回到连接池让后续线程继续使用。
    # 去连接池获取一个连接
    conn = POOL.connection()
    # print(th, '链接被拿走了', conn1._con)
    # print(th, '池子里目前有', pool._idle_cache, '\r\n')
    # 游标
    cursor = conn.cursor()
    rows = cursor.execute('select * from app01_user')
    result = cursor.fetchall()
    cursor.close()
    # conn.close()只是将连接放回连接池
    conn.close()
    print(num, '----->', result)

from threading import Thread

for i in range(57):
    t = Thread(target=task, args=(i, ))
    t.start()
View Code

 如果没有连接池,使用pymysql来连接数据库时,单线程应用完全没有问题,但如果涉及到多线程应用那么就需要加锁,一旦加锁那么连接势必就会排队等待,当请求比较多时,性能就会降低了。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pymysql
import threading
from threading import RLock

LOCK = RLock()
CONN = pymysql.connect(host='127.0.0.1',
                       port=3306,
                       user='root',
                       password='123',
                       database='pooldb',
                       charset='utf8')


def task(arg):
    with LOCK:
        cursor = CONN.cursor()
        cursor.execute('select * from tb1')
        result = cursor.fetchall()
        cursor.close()

        print(result)


for i in range(10):
    t = threading.Thread(target=task, args=(i,))
    t.start()
加锁
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pymysql
import threading
CONN = pymysql.connect(host='127.0.0.1',
                       port=3306,
                       user='root',
                       password='123',
                       database='pooldb',
                       charset='utf8')


def task(arg):
    cursor = CONN.cursor()
    cursor.execute('select * from tb1')
    result = cursor.fetchall()
    cursor.close()

    print(result)


for i in range(10):
    t = threading.Thread(target=task, args=(i,))
    t.start()
无锁(报错)

PS: 查看连接 show status like 'Threads%';

3)修改3.5的代码

模式一方式

import pymysql
from flask import Flask
from dbutils.persistent_db import PersistentDB
from dbutils.pooled_db import PooledDB

app = Flask(__name__)
# 连接池
POOL = PersistentDB(
    creator=pymysql,  # 使用链接数据库的模块
    maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
    setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
    ping=0,
    # 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
    closeable=False,
    # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
    threadlocal=None,  # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    database='router_auth',
    charset='utf8'
)


def fetchall(sql):
    conn = POOL.connection(shareable=False)
    # 游标
    cursor = conn.cursor()
    rows = cursor.execute(sql)
    result = cursor.fetchall()
    cursor.close()
    conn.close()

    return result


@app.route('/login')
def login():
    result = fetchall('select * from app01_user')
    print(result)
    return 'login'


@app.route('/index')
def index():
    result = fetchall('select * from app01_user')
    print(result)

    return 'index'


@app.route('/order')
def order():
    result = fetchall('select * from app01_user')
    print(result)

    return 'order'


if __name__ == '__main__':
    app.run()
View Code

模式一进阶版用法:基于函数

sqlhelper.py

import pymysql
from dbutils.persistent_db import PersistentDB
from dbutils.pooled_db import PooledDB

# 连接池
POOL = PersistentDB(
    creator=pymysql,  # 使用链接数据库的模块
    maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
    setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
    ping=0,
    # 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
    closeable=False,
    # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
    threadlocal=None,  # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    database='router_auth',
    charset='utf8'
)


def fetchall(sql, val):
    """获取多条数据"""
    conn = POOL.connection(shareable=False)
    # 游标
    cursor = conn.cursor()
    rows = cursor.execute(sql, val)
    result = cursor.fetchall()
    cursor.close()
    conn.close()

    return result


def fetchone():
    """获取单条数据"""
    pass
sqlhelper.py

普通的数据库连接.py

from flask import Flask
from sqlhelper import fetchall

app = Flask(__name__)


@app.route('/login')
def login():
    result = fetchall('select * from app01_user where username=%s', "alias")
    print(result)
    return 'login'


if __name__ == '__main__':
    app.run()
普通的数据库连接.py

 

模式一进阶版用法:单例

sqlhelper.py

import pymysql
from dbutils.persistent_db import PersistentDB
from dbutils.pooled_db import PooledDB


class SqlHelper(object):
    def __init__(self):
        self.pool = PersistentDB(
            creator=pymysql,  # 使用链接数据库的模块
            maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
            setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
            ping=0,
            # 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
            closeable=False,
            # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
            threadlocal=None,  # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置
            host='127.0.0.1',
            port=3306,
            user='root',
            password='123456',
            database='router_auth',
            charset='utf8'
        )

    def open(self):
        conn = self.pool.connection(shareable=False)
        # 游标
        cursor = conn.cursor()

        return conn, cursor

    def close(self, conn, cursor):
        cursor.close()
        conn.close()

    def fetchall(self, sql, val):
        """获取多条数据"""
        conn, cursor = self.open()
        rows = cursor.execute(sql, val)
        result = cursor.fetchall()
        self.close(conn, cursor)

        return result

    def fetchone(self):
        """获取单条数据"""
        pass


db = SqlHelper()
sqlhelper.py

普通的数据库连接.py

from flask import Flask
from sqlhelper import db

app = Flask(__name__)


@app.route('/login')
def login():
    result = db.fetchall('select * from app01_user where username=%s', "alias")
    print(result)
    return 'login'


@app.route('/index')
def index():
    result = db.fetchall('select * from app01_user')
    print(result)

    return 'index'


if __name__ == '__main__':
    app.run()
普通的数据库连接.py

 

 

模式二进阶版:

sqlhelper.py

import pymysql
from dbutils.persistent_db import PersistentDB
from dbutils.pooled_db import PooledDB


class SqlHelper(object):
    def __init__(self):
        self.pool = PersistentDB(
            creator=pymysql,  # 使用链接数据库的模块
            maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
            setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
            ping=0,
            # 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
            closeable=False,
            # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
            threadlocal=None,  # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置
            host='127.0.0.1',
            port=3306,
            user='root',
            password='123456',
            database='router_auth',
            charset='utf8'
        )

    def open(self):
        conn = self.pool.connection(shareable=False)
        # 游标
        cursor = conn.cursor()

        return conn, cursor

    def close(self, conn, cursor):
        cursor.close()
        conn.close()

    def fetchall(self, sql, val):
        """获取多条数据"""
        conn, cursor = self.open()
        rows = cursor.execute(sql, val)
        result = cursor.fetchall()
        self.close(conn, cursor)

        return result

    def fetchone(self):
        """获取单条数据"""
        pass


db = SqlHelper()
View Code

普通的数据库连接.py

from flask import Flask
from sqlhelper import db

app = Flask(__name__)


@app.route('/login')
def login():
    result = db.fetchall('select * from app01_user where username=%s', "alias")
    print(result)
    return 'login'


@app.route('/index')
def index():
    result = db.fetchall('select * from app01_user')
    print(result)

    return 'index'


if __name__ == '__main__':
    app.run()
View Code

 

再进一步,通过with上下文管理

sqlhelper.py

import pymysql
import threading
from dbutils.persistent_db import PersistentDB
from dbutils.pooled_db import PooledDB

"""
storage = {
    1111:{'stack': [(conn, cursor), ]}
}
"""


class SqlHelper(object):
    def __init__(self):
        self.pool = PersistentDB(
            creator=pymysql,  # 使用链接数据库的模块
            maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
            setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
            ping=0,
            # 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
            closeable=False,
            # 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)
            threadlocal=None,  # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置
            host='127.0.0.1',
            port=3306,
            user='root',
            password='123456',
            database='router_auth',
            charset='utf8'
        )
        self.local = threading.local()

    def open(self):
        conn = self.pool.connection(shareable=False)
        # 游标
        cursor = conn.cursor()

        return conn, cursor

    def close(self, conn, cursor):
        cursor.close()
        conn.close()

    def fetchall(self, sql, val):
        """获取多条数据"""
        conn, cursor = self.open()
        rows = cursor.execute(sql, val)
        result = cursor.fetchall()
        self.close(conn, cursor)

        return result

    def fetchone(self):
        """获取单条数据"""
        pass

    def __enter__(self):
        conn, cursor = self.open()

        rv = getattr(self.local, 'stack', None)
        if not rv:
            self.local.stack = [(conn, cursor), ]
        else:
            rv.append((conn, cursor))
            self.local.stack = rv
        return cursor

    def __exit__(self, exc_type, exc_val, exc_tb):
        rv = getattr(self.local, 'stack', None)
        if not rv:
            return
        conn, cursor = self.local.stack.pop()
        cursor.close()
        conn.close()


db = SqlHelper()
View Code

普通的数据库连接.py

from flask import Flask
from sqlhelper import db

app = Flask(__name__)


@app.route('/index')
def index():
    with db as cursor:
        rows = cursor.execute('select * from app01_user where username=%s', "alias")
        result = cursor.fetchall()
        print(result)

    return 'index'


if __name__ == '__main__':
    app.run()
View Code

 

posted @ 2020-05-07 17:58  耗油炒白菜  阅读(175)  评论(0编辑  收藏  举报