MySQL与python交互
用python代码来连接数据库,执行SQL语句,来查询到数据库中的数据。
当一张表中的数据量比较多时,而我们只需要查询其中的某个字段数据,直接查询会导致效率降低,此时就需要建立分表。
python操作MySQL步骤
安装pymysql
pip install pymysql
connection对象,建立与数据库的连接,创建对象:调用connect()方法。
cursor,游标,读取一行一行的数据
代码实现过程如下
# 第一种导入
# from pymysql import *
# connect()
# 第二种导入
import pymysql
# 1.连接数据库,user和password 都是直接设置的
conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',password='hww-sql',db='shopping',charset='utf8')
# 2.获取游标对象
cs = conn.cursor()
# 3. 通过游标对象执行sql语句,受影响的行数
r =cs.execute('select * from goods;')
print(r) # 得到的是数据的条数21
# 4. 获取数据,通过游标获取数据,执行完一行,游标会在第二行
print(cs.fetchone()) # 获取的是第一条数据
print(cs.fetchone()) # 获取的是第二条数据
# 4.1 fechmany(),默认不传参数,返回一条数据
print(cs.fetchmany())
print(cs.fetchmany(2)) # 括号内的数字是获取数据的条数
# 4.2 获取全部的数据
# print(cs.fetchall()) # 获取全部的数据
# 获取全部数据后,再去获取数据就得不到数据,返回None
# print(cs.fetchone()) # None,获取所有数据后,游标在末尾不会重新获取
# 5. 关闭
# 5.1 关闭游标
cs.close()
# 5.2 关闭连接
conn.close()
# 关闭后还可以获取数据,有缓存的
print('*'*50)
print(cs.fetchone())
异常捕获
当端口号等信息出现错误的时候,为了保证程序的正常运行,就需要进行异常捕获
import pymysql
try:
conn = pymysql.connect(host='127.0.0.1',port=3307,user='root',passwd='hww-sql',db='shopping',charset='utf8')
except Exception as e:
print(e) # e是对象,并不是元组,代表的是Exception
print(e.args[0]) # 取出第一个值 2003
封装DB
用类来做封装,单独分成模块,实现单独的某个功能。
from pymysql import *
'''
1.连接数据库,在实例化的时候连接数据库
2.实现程序执行完毕后,自动关闭
'''
class MyDb(object):
# 2.初始化,自动连接数据库
def __init__(self):
self.my_conn()
# 1.定义连接数据库的方法
def my_conn(self):
# 实例化方法
try:
self.conn = connect(host='127.0.0.1',port=3306,user='root',passwd='hww-sql',db='shopping',charset='utf8')
except Exception as e:
print(e)
# 3. 获取单条数据
def get_one(self):
# 3.1 获取游标
cs = self.conn.cursor()
# 3.2 执行sql语句
sql = 'select * from goods'
# 执行sql语句
cs.execute(sql)
# 3.3 获取执行的结果
res = cs.fetchone()
# 3.4 只关闭游标
cs.close()
return res
# 4. 获取全部数据
def get_all(self):
# 4.1 获取游标
cs = self.conn.cursor()
# 4.2 执行sql语句
sql = 'select * from goods'
# 执行sql语句
cs.execute(sql)
# 4.3 获取执行的结果
res = cs.fetchall()
# res = cs.fetchmany(5) # 传入参数值
# 4.4 只关闭游标
cs.close()
return res
# 关闭连接,需把关闭连接单独定义,否则第二次调用的时候连接就关闭了
# def close_conn(self):
# self.conn.close()
# 程序执行完毕之后,自动执行关闭的方法
def __del__(self):
self.conn.close()
def main():
# 实例化对象
db =MyDb()
# data =db.get_one() # 每次执行都会创建一个游标
# print(data)
# data = db.get_one() # 访问的始终的第一个数据,因为每次执行都重新创建一个游标
# print(data)
all_data = db.get_all()
# print(all_data)
# 遍历取出所有数据
for data in all_data:
print(data)
if __name__ == '__main__':
main()
首先导入库,用类进行封装,代码的框架为,定义类、函数main()、程序的入口。定义连接数据库的方法,用init方法在实例化的时候就自动进行连接数据库,然后是进行获取数据,获取单条数据,先获取游标,再执行sql语句,获取执行的结果,最后关闭游标和连接,把获取到的res 返回到main函数里函数的调用处。如果进行二次函数调用的话就报错,因为第一次调用后,与数据库的连接已经关闭了,为了反复获取数据,需要把关闭连接单独存放。关闭游标不用单独存放,因为方法调用的时候每次都重新定义了游标,所以每次取值都是从第一条数据开始取。定义获取多条数据的函数,跟获取单条数据的函数类似,在main函数里调用函数,获取到全部的数据,数据获取得到的是元组,可以用遍历的方法逐个取出。对代码进行优化,用del方法实现在代码执行结束的时候自动执行关闭连接。
插入数据
导入库,创建操作数据库的函数,进行数据库的连接、获取游标、插入数据、执行sql语句、关闭游标和连接。程序正常运行但是未能增加数据,此时为引擎的问题,MyIsAM 不需要提交事务就可以修改数据;Innodb 修改表的数据,需要进行提交事务(安全性更高),需要在关闭游标前用commit提交事务,此时数据表的内容就可以添加进去了。如果有多个sql语句,一个commit可以提交多个事务。添加数据语句发生错误,数据不能正常添加进去,但是会占用数据表中的id,因为服务器端会接收。
如果执行多条sql语句,只要有一条错误,就不进行添加,好比银行卡转钱,信息错误会自动返回原账户,可以用回滚来实现 conn.rollback()。用try,except来捕捉问题。
import pymysql
def coperation_db():
try:
# 连接数据库
conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='hww-sql',db='mytest-01',charset='utf8')
# 获取游标
cs = conn.cursor()
# 插入数据
sql = "insert into mytable1 (name) value ('xiaoming11');"
# 执行sql语句
cs.execute(sql)
# 插入数据
sql = "insert into mytable1 (name) value ('xiaoming22');"
# 执行sql语句
cs.execute(sql)
# 提交事务,一次性可以提交多个
conn.commit()
# 关闭游标
cs.close()
# 关闭连接
conn.close()
except Exception as e:
conn.rollback()
if __name__ == '__main__':
coperation_db()
使用面向对象完成商品的查询
'''
输入1:查询所有商品
输入2:所有商品种类
输入3:查询所有品牌
输入4:退出
输入5:插入数据
'''
import pymysql
class Shopping(object):
def __init__(self):
self.conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='hww-sql',db='shopping',charset='utf8')
self.cs =self.conn.cursor()
# 用户输入的模板
def run(self):
while True:
num = self.print_meun()
if num == '1':
self.show_all_goods()
elif num == '2':
self.show_all_cates()
elif num == '3':
self.show_all_brands()
elif num == '4':
break
elif num == '5':
self.add_cate()
else:
print('你输入的内容错误')
# 写入的内容不需要参数,不需要self
# 静态方法的装饰器
@staticmethod
def print_meun():
print('-----shop-----')
print('输入1:查询所有商品')
print('输入2:所有商品种类')
print('输入3:查询所有品牌')
print('输入4:退出')
print('输入5:插入数据')
num = input('请输入选项:')
return num
# 查询所有的商品,避免代码重复写,把执行sql语句,获取所有的结果,遍历循环得到的数据单独列出来
def show_all_goods(self):
sql = 'select * from goods'
self.excute_sql(sql)
# 查询所有的商品种类
def show_all_cates(self):
sql = 'select * from goods_cates'
self.excute_sql(sql)
# 查询所有的品牌,并进行去重
def show_all_brands(self):
sql = 'select distinct brand_name from goods'
self.excute_sql(sql)
# 添加商品分类
def add_cate(self):
name = input('请输入商品分类名字:')
# 要注意 value 后跟的是字符串,格式化字符串后得到数据不带引号,要在格式化字符串的时候加上引号
# f"-- insert into goods_cates (name) value (商品信息)"
sql = f"insert into goods_cates (name) value ('{name}')"
self.excute_sql(sql)
# 提交事务
self.conn.commit()
# 单独定义函数,执行sql语句,减少重复代码
def excute_sql(self,sql):
self.cs.execute(sql)
res = self.cs.fetchall()
for data in res:
print(data)
# 自动关闭连接
def __del__(self):
self.conn.commit()
def main():
shop = Shopping()
shop.run()
if __name__ == '__main__':
main()
导入库,搭建代码的框架,创建购物类,定义main函数,建立主程序的入口。在实例化对象,初始化的时候就进行连接数据库、获取游标对象。创建输入模板,用于用户进行选择,提示用户进入模块,提示用户输入,可以用whlie True进行死循环状态,一直进行输入。判断接收用户的输入是否为1-4,进行判断并分别执行不同的代码。输入模板函数种的self与一系列print没有关系,可以单独把print的内容拿出来,利用静态方法的装饰器,定义里面没有任何参数的函数,在while True里调用此函数。定义查询所有商品的函数,创建查询,执行sql语句,获取所有的结果,遍历循环得到的数据。然后定义所有商品种类、查询所有的品牌,函数中的执行sql语句、获取所有的结果、遍历循环内容都是重复的,可以把重复的内容进行单独的封装,单独定义函数用来执行sql语句,然后在每个函数里调用此方法。根据用户输入的内容,分别调用这几个函数。
视图
视图(view)是一种虚拟存在的表,对于使用视图的用户来说基本上是透明的,视图并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的.
- 定义视图
create view 视图名称 as select 语句;
- 查看视图,查看表的时候会把视图表页列出来
show tables;
- 使用视图
select * from v_pro;
- 删除视图
drop view 视图名称
视图的作用:
- 简单:提高了重用性,就像一个函数,避免代码的重复书写
- 安全:提高了安全性能,可以针对不同的用户,设定不同的视图,比如公司的薪水不让别人查看,可以构建一个不带薪水的视图,供员工查看
- 数据独立:一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响
有以下内容出现,不能进行视图的修改。
- select子句中包含distinct、组函数
- select语句中包含group by、order by子句以及相关子查询
- from子句中包含多个表
- 如果视图中有计算量,则不能更新
- 如果基表中有某个具有非空约束的列未出现在视图定义中,则不能做insert操作