装置
装置 mysql 数据库的难度和 oracle 数据库几乎没得比,装置步骤如下:
装置 MariaDB
yum install mariadb mariadb-server # 装置,centos7 默认的 mysql 就是 mariadb
systemctl start mariadb # 启动 mariadb
systemctl enable mariadb # 开机自启动
mysql_secure_installation # 设置 root 明码
mysql -uroot -p # 登录
装置 pymysql
pip install pymysql
基本操作
数据库基本操作次要是:
- 创立连贯
- 获取游标
- 执行 sql
- 提交事务:针对非查问性 SQL
代码
import pymysql
# connect 函数关上数据库连贯
conn = pymysql.connect(host='192.168.110.13', user='root', password='123456', database='student')
# cursor 办法创立游标对象 cur
cur = conn.cursor()
# execute 办法执行 SQL 语句
cur.execute("SELECT VERSION()")
# fetchone 办法获取单条数据
data = cur.fetchone()
print ('Database version : {}'.format(data))
# 敞开游标
cur.close()
# 敞开数据库连贯
conn.close()
<!–more–>
DDL
DDL:数据定义语言。包含创立表,创立索引等等
import pymysql
# connect 函数关上数据库连贯
conn = pymysql.connect(host='192.168.110.13', user='root', password='123456', database='student')
# cursor 办法创立游标对象 cur
cur = conn.cursor()
# 创立表
sql = '''create table user (name char(20) not null,
age int,
sex char(1))'''
cur.execute(sql)
# 敞开游标
cur.close()
# 敞开数据库连贯
conn.close()
DML
DML:数据操作语言,蕴含增删改三项操作。
insert
import pymysql
# connect 函数关上数据库连贯
conn = pymysql.connect(host='192.168.110.13', user='root', password='123456', database='student')
# cursor 办法创立游标对象 cur
cur = conn.cursor()
# 创立表
sql = '''insert into user(name, age, sex) values('suncle', 18,'m')'''
try:
# 执行 sql 语句
cur.execute(sql)
# 提交到数据库执行
conn.commit()
except:
# 如果产生谬误则回滚
conn.rollback()
# 敞开游标
cur.close()
# 敞开数据库连贯
conn.close()
update
import pymysql
# connect 函数关上数据库连贯
conn = pymysql.connect(host='192.168.110.13', user='root', password='123456', database='student')
# cursor 办法创立游标对象 cur
cur = conn.cursor()
# 创立表
sql = '''update user t set t.age = 20 where t.name='suncle''''
try:
# 执行 sql 语句
cur.execute(sql)
# 提交到数据库执行
conn.commit()
except:
# 如果产生谬误则回滚
conn.rollback()
# 敞开游标
cur.close()
# 敞开数据库连贯
conn.close()
delete
import pymysql
# connect 函数关上数据库连贯
conn = pymysql.connect(host='192.168.110.13', user='root', password='123456', database='student')
# cursor 办法创立游标对象 cur
cur = conn.cursor()
# 创立表
sql = '''delete from user where age=20'''
try:
# 执行 sql 语句
cur.execute(sql)
# 提交到数据库执行
conn.commit()
except:
# 如果产生谬误则回滚
conn.rollback()
# 敞开游标
cur.close()
# 敞开数据库连贯
conn.close()
QUERY
根底查问
次要有三个函数
- cursor.fetchall 返回行的元组
- cursor.fetchmany 返回行的元组,能够指定返回前 N 行 相当于对 fetchall 切片 fetchall[:N]
- cursor.fetchone 返回首行,相当于 fetchall[0]
查问语句如下:
cur.execute('''select * from user t where t.age<=19;''')
三种办法失去的后果别离为:
cur.fetchall() # (('suncle', 18, 'm'), ('suncle1', 19, 'm'))
cur.fetchmany(1) # (('suncle', 18, 'm'),)
cur.fetchone() # ('suncle', 18, 'm')
可见:每行数据也是一个元组,元组的内容由 sql 决定
如果要让返回的数据带上列名,也就是要返回字典,那么就须要用到 cursors.DictCursor。
DictCursor
创立 cursor 时创立 DictCursor 类型的就能够 fetch 回来字典模式的后果了
代码
import pymysql
conn = pymysql.connect(host='192.168.110.13', user='root', password='123456', database='student')
# 创立 cursor 时指定 cursor 参数 cursor=pymysql.cursors.DictCursor 示意 cursor 类型
cur = conn.cursor(cursor=pymysql.cursors.DictCursor)
cur.execute('''select * from user t where t.age<=20;''')
cur.fetchall()
fetchall 返回后果为:
[{'age': 18, 'name': 'suncle', 'sex': 'm'},
{'age': 19, 'name': 'suncle1', 'sex': 'm'},
{'age': 20, 'name': 'suncle2', 'sex': 'm'}]
返回每一行记录都是一个字典,整体后果是由字典组成的列表。而默认的 cursor 是由元组组成的元组。
参数化查问
根底的 SQL 注入
import pymysql
conn = pymysql.connect(host='192.168.110.13', user='root', password='123456', database='student')
cur = conn.cursor()
def get_user(age=18):
sql = '''select * from user t where t.age<={};'''.format(age)
cur.execute(sql)
return cur.fetchall()
get_user() # 返回(('suncle', 18, 'm'),)
get_user('18 or 1=1') # 返回(('suncle', 18, 'm'), ('suncle1', 19, 'm'))
当传入参数的 age 中带 sql 条件的时候,就会产生 sql 注入,使得后果可能并不满足要求。
为了解决 sql 注入,咱们能够应用参数化查问。
应用参数化查问
以上代码做以下批改之后就能够防止 sql 注入
import pymysql
conn = pymysql.connect(host='192.168.110.13', user='root', password='123456', database='student')
cur = conn.cursor()
def get_user(age=18):
# 不论数据库定义的是什么类型,对立应用 %s
sql = '''select * from user t where t.age<=%s;'''.format(age)
cur.execute(sql, (age,)) # 参数化查问
return cur.fetchall()
参数化查问最大的劣势在于防止了 SQL 注入,同时参数化之后防止了 sql 屡次硬解析,能进步查问效率。所以,总是应该应用参数化查问。
上下文治理
数据库连贯和游标都反对上下文治理。
游标
查看 cur 实例对应 Cursor 类的办法
cur = conn.cursor()
help(cur)
对应的 with 语句应用如下
with cur:
cur.execute('''select * from user''')
cur.execute('''select * from user''') # 抛出谬误:ProgrammingError: Cursor closed
with 语句块完结之后 cur 就曾经敞开了。
连贯
通过 help 命令查看 Connection 类的 __enter__
和__exit__
两种办法的实现
conn = pymysql.connect(host='192.168.110.13', user='root', password='123456', database='student')
help(conn) # conn 是 Connection 类
查看后果如下:
| __enter__(self)
| Context manager that returns a Cursor
|
| __exit__(self, exc, value, traceback)
| On successful exit, commit. On exception, rollback
__enter__
办法会返回一个游标__exit__
办法:如果胜利推出就会主动提交 commit,如果产生异样就会回滚 rollback
对应的 with 语句应用如下
with conn as cur:
cur.execute('''update user t set t.age = 20 where t.name='suncle'''')
cur.execute('''select * from user''') # 退出 with 块之后游标依然没有敞开
尽管游标没有敞开,然而数据库操作曾经提交。
游标和连贯独特上下文治理
with conn as cur:
with cur:
cur.execute('''update user t set t.age = 20 where t.name='suncle'''')
退出整个上下文治理块之后,游标会敞开,并且会主动提交。
数据库连接池
一般来说,应用程序拜访数据库的过程是:
- 装载数据库驱动程序
- 建设数据库连贯
- 拜访数据库,执行 sql 语句
- 断开数据库连贯
绝对于性能失常的 SQL 的执行效率来说,建设连贯是一个费时的流动,而且零碎还要为每一个连贯分配内存资源。在当初 web 申请的大并发量状况下,必然会导致频繁的数据库操作。而频繁的进行数据库连贯操作势必占用很多的系统资源,使得零碎的响应速度降落,重大的甚至会造成服务器的解体。
引入数据库连接池技术之后,应用程序拜访数据库的过程是:
- 申请数据库操作时,从连接池中取出创立好的数据库连贯
- 执行 sql 语句
- 一直开数据库连贯,而是放回连接池中,期待下次应用
连接池还有个长处就是能管制数据库的压力,当大量用户同时涌入时,连接池只会应用池限度数据库连贯数目,而不会不停的向数据库申请连贯,最初导致服务器解体。
Python 实现数据库连接池
- 应用队列 Queue 保留数据库连贯
代码如下
from queue import Queue
import pymysql
class ConnectionPool(): # args 和 kwargs 用来接管数据库 url 信息
def __init__(self, size, *args, **kwargs):
self.args = args
self.kwargs = kwargs
self.size = size
self.pool = Queue(maxsize=self.size)
for _ in range(self.size):
self.pool.put(self._connect())
def _connect(self):
return pymysql.connect(*self.args, **self.kwargs)
@staticmethod
def _close(conn):
conn.close()
def get_connection(self):
return self.pool.get()
def return_connection(self, conn):
return self.pool.put(conn)
def close_pool(self):
while not self.is_empty():
self._close(self.pool.get())
def is_empty(self):
return self.pool.empty()
def is_full(self):
return self.pool.full()
def current_connection_count(self):
return self.pool.qsize()
pool = ConnectionPool(20, host='192.168.110.13', user='root', password='123456', database='student')
conn = pool.get_connection() # 获取数据库连贯
print(conn) # <pymysql.connections.Connection at 0x7f6290300940>
print(pool.current_connection_count()) # 19
cur = conn.cursor()
cur.execute("SELECT VERSION()")
data = cur.fetchone()
print ('Database version : {}'.format(data[0]))
cur.close()
pool.return_connection(conn) # 敞开游标之后须要回收数据库连贯
print(pool.current_connection_count()) # 20
记得帮我点赞哦!
精心整顿了计算机各个方向的从入门、进阶、实战的视频课程和电子书,依照目录正当分类,总能找到你须要的学习材料,还在等什么?快去关注下载吧!!!
朝思暮想,必有回响,小伙伴们帮我点个赞吧,非常感谢。
我是职场亮哥,YY 高级软件工程师、四年工作教训,回绝咸鱼争当龙头的斜杠程序员。
听我说,提高多,程序人生一把梭
如果有幸能帮到你,请帮我点个【赞】,给个关注,如果能顺带评论给个激励,将不胜感激。
职场亮哥文章列表:更多文章
自己所有文章、答复都与版权保护平台有单干,著作权归职场亮哥所有,未经受权,转载必究!