Flush PRIVILEGES; -- 刷新权限并生效
6)查看授权
- 查看当前用户: show grants;
-查看其他用户: show grants for '用户名'@'客户端';
7)吊销权限(取消用户的某个权限)
- 语法: revoke 权限列表 on 库名.表名 from '用户名'@'客户端地址'
- 示例: 吊销Daniel用户所有库,所有列表的插入数据权限
revoke insert on *.* from 'bank_user'@'%';
revoke insert on bank.* from 'bank_user'@'%';
4. 数据库事务(重点)
- 事务(Transacyion):
- 数据库执行一系列操作时,全都执行,全都不执行
保证数据的一致性、正确性
- 例如在一笔转账中,执行需要三个操作,
从转出账户减去相应金额
在转入账户增加相应金额
登记一笔转账明细
以上三个操作,要么全部成功,要么全部失败
3)使用事务的情况
- 涉及到多表的增删改操作
- 执行这些操作时需要保证一致性,正确性
4)启用事务条件要求:必须是Innodb存储引擎
5)事务的额特征(ACID):
- 原子性(Atomicity):事务是一个整体,要么全部执行,要么全部不执行
- 一致性(Consis.
tency):事务执行完成后,从一个一致状态变成另一个一致状态
- 隔离性(Isolation):不同的事务不会相互影响,干扰
- 持久性(Durability):一旦事务提交,对数据库的修改就必须永久保留下来
6)如何进行事务操作
- 开启: start transaction
- 提交: commit
- 回滚:rollback
- 示例:在两个账户间进行转账
第一步:减去转出账户余额
第二步:在转入账号上加上相等的余额
提交事务
start transaction;
update acct_new set balance = balance - 100
where acct_no = '6223450001';
update acct_new set balance = balance + 100
where acct_no ='622456000020';
commit;---或rollback
----在提交事务前,重新登录一个客户端
----查看数据是否变更
7)SQL语句分类
- 数据查询语言(DQL):查询数据,不改变数据
- 数据定义语言(DDL):定义数据结构,如建表/库,删除库/表,创建/删除索引,修改表结构
- 数据操作语言(DML):对数据进行增删改
- 数据控制语言(DCL):权限管理,事务操作,数据库监视...
-------------------------------------------------day25.new---------------------------------------------------
1.锁
1)锁:对数据库的控制权
2)目的:解决多个工作单元并发操作数据的正确性
3)分类:
a)锁类型
- 读锁(共享锁):加锁后,可以读取,但不能修改
- 写锁(排它锁):加锁后,不能进行读写
b)锁粒度
- 行级锁(细粒度):锁定一行,并发效率高
控制较为复杂,消耗资源多
- 表级锁(粗粒度):锁定整张表,并发效率低
控制简单,消耗资源较少
2.存储引擎
1)什么是存储引擎:表的存储方式,包括存储机制,索引机制,锁定方式等
2)基本操作:
- 查看:show engines;
- 查看某个表的存储引擎方式:show create table 表名
-建表时指定存储引擎
create table t1(id int primary key)engine=InnoDB default charset=utf8;
engine 指定存储
- 修改存储引擎方式
alter table t1 engine = MyISAM;
3)常见存储引擎
a)InooDB
特点:支持事务,行级锁,外键
共享表空间
*.frm 表结构和索引
*.ibd 表记录
show global variables like '%datadir'命令查看数据存储位置
sudo -i切换到root用户,进入目录查看
- 使用场合
更新操作密集的表
有数据库事务支持的要求
自动灾备,恢复
有外键约束要求
支持自增长字段(auto_increment)
b)MyISAM
- 支持表级锁定、不支持事务、不支持外键
不支持行锁定,访问速度较快
- 独享表空间
表名.frm: 表结构
表名.myd: 表数据
表名.myi: 表索引
- 适用场合
查询操作较多
数据一致性要求较低(不支持事务)
没有外键约束
c)Memory(内存表):
- 表结构存储在磁盘上(硬盘),数据存储在内存
访问速度很快
- 文件:表名.frm 存储表结构
- 服务(或机器)重启后,表中的数据丢失
- 适用场合:
数据量小、访问速度要求极快、访问频率高、
数据丢失后不会造成影响
- 示例:
1:创建memory引擎的表
create table t2(id int)engine=memory;
2:插入数据并查询
3:重启服务,再查询,数据消失
sudo /etc/init.d/mysql restart
3. E-R模型:实体关系模型
a)实体(Entry): 现实中可以区分的事物称之为实体
b)关系(Relationship): 实体之间的联系
- 一对一
- 一对多
- 多对多
c)属性:实体所具有的数据特征
d)E-R图:用图形化方式,表达实体间的关系
矩形:表示实体
椭圆:实体的属性
菱形:实体间的关系
一对一:菱形左右各写一个1
一对多:菱形左右分别用1,N来表示
多对多:菱形左右分别用M, N来表示
e)练习:画出账户,交易明细,客户实体之间的E-R图(见ER图.pptx)
4. 使用Python访问MySQL
1)pymysql库:Python语言访问MySQL接口
- 安装:
在线:sudo pip3 install pymysql
离线:
第一步:下载安装包,下载地址:
https://pypi.org/project/PyMySQL/
PyMySQL-0.9.3.tar.gz
第二步:解压包,并执行安装
tar -zxvf PyMySQL-0.9.3.tar.gz
cd PyMySQL-0.9.3
第三步:进入目录,安装
python3 setup.py install
- 验证:进入Python交互模式,执行导入包操作
import pymysql
如果不报错,则说明安装成功
# 第一步:导入pymysql模块
import pymysql
host = 'localhost'#服务器地址
user = 'root'#用户名
passwd = '123456'#密码
dbname = 'bank'#库名称
#第二步:建立到数据库服务器的连接,创建连接对象
conn = pymysql.connect(host,user,passwd,dbname)
#第三步:获取游标对象(cursor),通过调用数据库连接 对象获得游标
cursor = conn.cursor()
#第四步:利用cursor对象提供的方法,执行SQL语句
cursor.execute("select * from acct_new")
result = cursor.fetchall()#取查询到的数据
for r in result:
tmp = "帐号:%s,户名:%s,金额:%s"%(r[1],r[1],r[6])
print(tmp)
#第五步:提交事务(如果需要)
#第六步:关闭游标对象
cursor.close()
#第七步:关闭数据库连接对象
conn.close()
2)PyMySQL访问MySQL的流程
第一步:导入pymysql模块
第二步:建立到数据库服务器的连接,创建连接对象
第三步:创建游标对象(cursor),通过调用数据库连接
对象获得游标
第四步:利用cursor对象提供的方法,执行SQL语句
第五步:提交事务(如果需要)
第六步:关闭游标对象
第七步:关闭数据库连接对象
3)PyMySQL模块的主要方法
- connect: 连接数据库
参数:host 服务器地址
port 服务器端口(省略连默认端)
user 用户名
passwd 密码
db 数据库名称
charset 指定编码格式
- connection连接对象支持的方法
cursor() 获取游标
commit() 提交事务
rollback() 回滚事务
close() 关闭游标
- cursor游标对象支持的方法
execute(sql) 执行SQL语句
fetchall() 取得查询结果集中的所有数据
fetchone() 取查询结果集中一笔数据
fetchmany(size) 取得指定笔数数据
close() 关闭游标对象
只读属性:
rowcount 返回修改影响的笔数
4)示例:
示例1:查询
# pymysql查询示例
import pymysql
from db_conf import * #导入配置
#建立到数据库服务器的连接,创建连接对象
conn = pymysql.connect(host, user,
password, dbname)
#创建游标对象(cursor),通过调用数据库连接
#对象获得游标
cursor = conn.cursor()
#利用cursor对象,执行SQL语句
sql = "select * from acct"
cursor.execute(sql) #执行SQL语句
#取出查询结果,并打印
result = cursor.fetchall() #result是元组
for r in result: #遍历result
acct_no = r[0] #账号
acct_name = r[1] #户名
if r[6]: #判断是否为空值
balance = float(r[6]) #余额
else:
balance = 0.00 #余额为空设置为0
print("账号:%s, 户名:%s, 余额:%.2f" %
(acct_no, acct_name, balance))
#关闭游标对象
cursor.close()
#关闭数据库连接对象
conn.close()
示例2:插入
# pymysql的插入示例
import pymysql
from db_conf import * #导入配置
try:
conn = pymysql.connect(host, user,
password, dbname) #连接数据库
cursor = conn.cursor() #获取游标
#执行SQL语句
sql = '''insert into
acct(acct_no, acct_name, cust_no,
acct_type, reg_date, status, balance)
values('622345000010','Robert', 'C0010',
1, date(now()), 1, 33.00)'''
print(sql)
cursor.execute(sql) #执行
conn.commit() #提交事务
print("Insert OK")
except Exception as e:
print("数据库插入异常")
print(e)
finally:
cursor.close() #关闭游标
conn.close() #关闭连接
示例3:修改
import pymysql
from db_conf import * #导入配置
try:
conn = pymysql.connect(host, user,
password, dbname) #连接数据库
cursor = conn.cursor() #获取游标
#执行SQL语句
sql = '''update acct
set balance = balance + 1000
where acct_no='622345000010'
'''
cursor.execute(sql) #执行
conn.commit() #提交事务
print("修改笔数:%d" % cursor.rowcount)
except Exception as e:
print("数据库修改异常")
print(e)
finally:
cursor.close() #关闭游标
conn.close() #关闭连接
示例4:删除
# pymysql删除示例
import pymysql
from db_conf import * #导入配置
try:
conn = pymysql.connect(host, user,
password, dbname) #连接数据库
cursor = conn.cursor() #获取游标
#执行SQL语句
sql = '''delete from acct
where acct_no='622345000010'
'''
cursor.execute(sql) #执行
conn.commit() #提交事务
print("删除笔数:%d" % cursor.rowcount)
except Exception as e:
print("数据库删除异常")
print(e)
finally:
cursor.close() #关闭游标
conn.close() #关闭连接
课堂作业:账户管理修改、删除功能添加上
5. SQL语句优化
1)在经常查询、排序的字段上建立索引
2)尽量少使用不等于条件判断,不等于会放弃使用索引
3)少使用null值判断,null值判断会放弃使用索引
4)条件判断少使用or连接,in,not in
5)模糊查询避免%前置
6)查询时如果select *,直接写成字段名会提高效率
7)尽量少在where子句中,使用字段进行运算。例如:
select * from acct where balance / 2 > 5000
8)数值类型的字段,进行条件比较时,一般比
字符串比较效率更高
作业:完善账户管理系统的修改、删除功能
账户管理系统启动时,增加登录功能
(原理:打印菜单前,先输入用户名、密码
并到数据库自建的用户表中查询
如果用户名、密码匹配,则登录成功)
1 #账户类 2 class Acct: 3 def __init__(self,acct_no,acct_name,acct_type,balance): 4 self.acct_no=acct_no 5 self.acct_name=acct_name 6 self.acct_type = acct_type 7 self.balance = balance 8 def __str__(self): 9 ret = "账号:%s,户名:%s,类型:%d,余额:%.2f"%(self.acct_no,self.acct_name,self.acct_type,self.balance) 10 return ret
1 #账户管理类(业务逻辑层) 2 #实现账户新增,修改,删除等逻辑处理 3 #账户类,仅用于数据传输 4 from db_oper import * 5 from acct import * 6 class AccMange:#账户管理类 7 def __init__(self,db_oper): 8 self.db_oper = db_oper#数据访问对象 9 #查询所有庄户信息 10 def query_all_acct(self): 11 accts =[]#返回的Acct对象列表,可能有多个对象 12 #拼装所需要的SQL 13 sql = "select * from acct_new" 14 #执行查询 15 result = self.db_oper.do_query(sql) 16 if not result: 17 print("查询结果为空") 18 return None 19 #返回结果:实例化一个Acct对象列表返回 20 for r in result:#便利数据集 21 acct_no = r[0]#账户 22 acct_name = r[1]#姓名 23 acct_type =int(r[3])#类型 24 balance = r[6]#金额 25 accts.append(Acct(acct_no,acct_name,acct_type,balance)) 26 return accts#返回对象列表 27 #根据账户查询,最多返回一个Acct对象 28 29 def query_by_id(self,acct_no): 30 sql = "select * from acct_new where acct_no = %s" % acct_no 31 result = self.db_oper.do_query(sql)#执行查询 32 if not result: 33 print("查询返回空对象") 34 return None 35 #提取查询结果,实例化一个Acct对象返回 36 r = result[0]#取得第一行数据 37 acct_no = r[0]#账号 38 acct_name = r[1]#户名 39 acct_type = int(r[3])#类型 40 balance = r[6]#余额 41 return Acct(acct_no,acct_name,acct_type,balance) 42 43 def insert_acct(self,acct_new):#插入 44 sql = '''insert into acct_new(acct_no,acct_name,acct_type,balance)values('%s','%s',%d,%.2f)'''%(acct_new.acct_no,acct_new.acct_name,acct_new.acct_type,acct_new.balance) 45 print(" sql:%s "%sql) 46 result =self.db_oper.do_update(sql) 47 print("执行结构,影响行数:%d"%result) 48 return 49 50 def update_acct(self,acct_new):#更新 51 sql="update acct set acct_type =%d,balance = %.2f where acct_no='%s'"%(acct_new.acct_type,acct_new.balance,acct_new.acct_no) 52 print(" sql:%s "%sql) 53 result = self.db_oper.do_update(sql) 54 print("执行结束,影响行数:%d"%result) 55 return 56 57 def query_by_name(self,acct_name):#模糊? 58 if not acct_name: 59 print("户名对象非法") 60 return None 61 if acct_name =="": 62 print("用户名不能为空") 63 return None 64 65 accts =[] 66 sql = "select * from acct_new where acct_name ='%s'" % acct_name 67 68 result = self.db_oper.do_query(sql) 69 if not result: 70 print("查询返回空对象") 71 return None 72 73 for acct_info in result: 74 acct_no = acct_info[0] 75 acct_name = acct_info[1] 76 acct_type = int(acct_info[3]) 77 balance = acct_info[6] 78 accts.append(Acct(acct_no,acct_name,acct_type,balance)) 79 return accts 80 81 if __name__=="__main__": 82 db_oper = DBOper()#实例化访问对象 83 db_oper.open_conn()#打开数据库连接 84 85 am = AccMange(db_oper)#实例化AcctMange对象 86 db_oper.close_conn() 87
1 #ui 2 from db_oper import * 3 from acct_manager import * 4 from acct import * 5 6 #全局变量 7 db_oper = None#打印主菜单 8 am =None 9 def print_menu():#打印主菜单 10 #根据用户输入,进行不同操作 11 menu = '''----------请选取要执行的操作--------- 12 1-查询所有 4-新增账户 13 2-根据用户查询 5-修改账户 14 3-根据用户名查询 6-删除账户 15 ''' 16 print(menu) 17 def query_all():#查询所有账户 18 accts = am.query_all_acct() 19 for a in accts: 20 print(a) 21 22 def query_by_id(): 23 acct_no = input("请输入要查询的账号:") 24 if not acct_no: 25 print("输入账号不合法") 26 return 27 28 acct= am.query_by_id(acct_no) 29 print(" 查询结果:") 30 print(acct)#打印账户信息 31 print(" ") 32 33 def query_by_name():#根据用户名查询 34 acct_name = input("请输入要查询的户名:") 35 if not acct_name: 36 print("输入账号不合法") 37 return 38 39 accts =am.query_by_name(acct_name) 40 print(" 查询结果:") 41 for acct in accts: 42 print(acct)#打印账户信息 43 print(" ") 44 45 def add_acct(): 46 try: 47 acct_no = input("请输入账号:") 48 acct_name = input("请输入户名:") 49 acct_type = int(input("请输入账户类型(1-借记卡 2-理财卡 3-代缴代扣卡):")) 50 balance = float(input("请输入开户金额:")) 51 assert acct_type in [1, 2, 3] 52 assert balance >= 0.000001 53 54 new_acct =Acct(acct_no,acct_name,acct_type,balance) 55 am.insert_acct(new_acct) 56 except Exception as e: 57 print("操作错误") 58 print(e) 59 return 60 61 def update_acct(): 62 try: 63 acct_no = input("请输入账号:") 64 acct_name = input("请输入户名:") 65 acct_type = int(input("请输入账户类型(1-借记卡 2-理财卡 3-代缴代扣卡):")) 66 balance = float(input("请输入开户金额:")) 67 68 assert acct_type in [1, 2, 3] 69 assert balance >= 0.000001 70 71 new_acct = Acct(acct_no,acct_name,acct_type,balance) 72 am.update_acct(new_acct) 73 except Exception as e: 74 print("操作错误") 75 print(e) 76 return 77 #主函数 78 def main(): 79 global db_oper 80 global am 81 db_oper = DBOper()#实例化数据访问对象 82 db_oper.open_conn()#打开数据库连接 83 am = AccMange(db_oper)#实例化AccMange对象 84 85 while True: 86 print_menu() 87 oper = input("请选则要执行的操作:") 88 if oper == "1": #查询所有账户 89 query_all() 90 elif oper == "2": #根据账号查询 91 query_by_id() 92 elif oper == "3": #根据户名查询 93 query_by_name() 94 elif oper == "4": #新增账户 95 add_acct() 96 elif oper == "5": #修改账户 97 update_acct() 98 elif oper == "6": #删除账户 99 pass 100 else: 101 break 102 db_oper.close_conn() 103 104 if __name__ == "__main__": 105 main()
1 #数据库配置 2 host = 'localhost'#服务器地址 3 user = 'root'#用户名 4 passwd = '123456'#密码 5 dbname = 'bank'#库名称
1 #数据库访问类 2 import pymysql 3 import db_conf 4 class DBOper: 5 #构造方法 6 def __init__(self): 7 self.host =db_conf.host 8 self.user =db_conf.user 9 self.passwd =db_conf.passwd 10 self.dbname =db_conf.dbname 11 self.db_conn = None#数据库的连接对象 12 13 #连接数据库 14 def open_conn(self): 15 try: 16 self.db_conn = pymysql.connect(self.host,self.user,self.passwd,self.dbname) 17 except Exception as e: 18 print("连接数据库失败") 19 print(e) 20 else: 21 print("连接数据库成功") 22 #关闭连接 23 def close_conn(self): 24 try: 25 self.db_conn.close() 26 except Exception as e: 27 print("连接数据库失败") 28 print(e) 29 else: 30 print("关闭数据库成功") 31 32 #执行查询返回结果集 33 def do_query(self,sql): 34 if not sql:#参数合法性判断 35 print("sql语句不合法") 36 return None 37 if sql == "":#参数合法性判断 38 print("sql语句不合法") 39 return None 40 41 try: 42 cursor = self.db_conn.cursor()#获取游标 43 cursor.execute(sql)#执行sql语句 44 result = cursor.fetchall()#获取数据 45 cursor.close()#关闭游标 46 return result#返回查询数据集 47 except Exception as e: 48 print("查询出错") 49 print(e) 50 return None 51 52 53 #执行增删改等变更操作 54 def do_update(self,sql): 55 if not sql:#参数合法性判断 56 print("sql语句不合法") 57 return None 58 if sql == "":#参数合法性判断 59 print("sql语句不合法") 60 return None 61 62 try: 63 cursor = self.db_conn.cursor()#获取游标 64 result = cursor.execute(sql)#执行SQL语句 65 self.db_conn.commit()#提交事物 66 cursor.close() 67 return result#返回受影响的笔数 68 except Exception as e: 69 print("执行sql语句出错") 70 print(e) 71 return None 72 73 #测试 74 if __name__=="__main__": 75 dboper = DBOper() 76 dboper.open_conn() 77 ret = dboper.do_query("select * from acct_new") 78 for x in ret: 79 print(x) 80 81 ret = dboper.do_update("update acct_new set balance = balance + 100 where acct_no = '6223456000 '") 82 83 print(ret) 84 #查询 85 # result = dboper.do_query("select * from acct_new") 86 # for x in result: 87 # print(x) 88 89 # dboper.close_conn()#关闭数据库连接 90 91 #修改数据测试 92 # sql = '''update acct_new set balance = balance +1000 where acct_no ="6223456000"''' 93 # ret = dboper.do_update(sql) 94 # if not ret:#返回空对象,出错 95 # print("执行修改错误") 96 # #非空对象,执行成功 97 # else: 98 # print("影响笔数:%d"% ret) 99 # dboper.close_conn()#关闭数据库连接 100 101 102 103