前言:
相信了解到这里,对MySQL数据库也有了一定的了解,那么我们再来学习一下较为重要的内容,数据备份,使用备份的目的也很简单, 防止数据遗忘或者丢失等等,通过备份文件就可以恢复备份时的数据内容,通常备份需要定期来执行。以及在Python内如果操作数据,让我们来了解一下这些内容吧。
MySQL数据备份
备份方式有以下几种:
- 物理备份: 直接复制数据库文件,适用于大型数据库环境。但不能恢复到异构系统中如Windows。
- 逻辑备份: 备份的是建表、建库、插入等操作所执行SQL语句,适用于中小型数据库,效率相对较低。
- 导出表: 将表导入到文本文件中。
使用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
恢复逻辑备份
恢复备份的两种两种方式
方式一:
# 针对单库备份的恢复,将备份文件里面的表,全部恢复到某个库下面
mysql -uroot -p密码(可省略,密文输入) 库名 < 备份文件.sql
# 针对多库备份的恢复,将备份文件里面的多个库及表的结构记录,全部创建出来
mysql -uroot -p密码(可省略,密文输入) < 备份文件.sql
# 不需要输入库名
方式二:
# 当备份文件内是单个库时,我们需要将它恢复到某个库下面,这里就创建一个库
create database lll;
use lll;
source /xxx/xxx/备份文件.sql
# 当备份文件内是多个库时,我们不需要将它恢复到某张表下面,可以直接执行
source /xxx/xxx/备份文件.sql
这里补充一个删除库或者表的特殊语句,就是当库存在时则正常删除,如果不存在时,则发出警告信息,不会报错
drop table if exists 表名;
sdf这个库是不存在的,但是这条SQL语句还是成功执行了,没有报错,但是抛出了警告。
PyMySQL模块的使用
PyMySQL是Python3.x版本的一个模块,其主要作用就是用于连接MySQL数据库,本文将介绍使用PyMySQL连接数据库,并实现增删改查等功能。
在使用之前我们要确保PyMySQL的安装,如果还未安装可以使用:
pip3 install PyMySQL
当然也可以在pycharm内安装
环境准备
在使用PyMySQL开始本次练习前,需要先建立实验表
create database pymysql_test; # 创建实验所需库
CREATE TABLE student (
id int not null auto_increment primary key,
name varchar(30),
age int,
)
INSERT INTO `student` VALUES (1, 'jack', 18);
INSERT INTO `student` VALUES (2, 'tom', 19);
INSERT INTO `student` VALUES (3, 'jams', 23);
INSERT INTO `student` VALUES (4, 'rouse', 21);
INSERT INTO `student` VALUES (5, 'mark', 25);
实例
import pymysql
conn = pymysql.connect( # 连接MySQL数据库
host='127.0.0.1',
port=3306,
database='student',
user='登录MySQL的用户',
password='用户密码'
)
# 创建游标对象,用于操作数据库
cursor = conn.cursor() # 以元组的方式显示我们接收到的内容
# cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 改变显示方式为字典
cursor.execute("select * from student;")
data = cursor.fetchall() # 获取查询到的所有数据
print(data)
执行结果
# 元组显示
((1, 'jack', 18), (2, 'tom', 19), (3, 'jams', 23), (4, 'rouse', 21), (5, 'mark', 25))
# 如果改变显示为字段方式,则会显示出每个数据对应的字段
[{'id': 1, 'name': 'jack', 'age': 18}, {'id': 2, 'name': 'tom', 'age': 19}, {'id': 3, 'name': 'jams', 'age': 23}, {'id': 4, 'name': 'rouse', 'age': 21}, {'id': 5, 'name': 'mark', 'age': 25}]
插入数据
以下实例通过SQL语句向student表插入数据
mport pymysql
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
database='pymysql_test',
user='root',
password='password'
)
# 创建游标对象,用于操作数据库
cursor = conn.cursor()
sql = '''
insert into student values(null,'张三',26),(null,'李四',29);
'''
try:
cursor.execute(sql) # 执行SQL语句
conn.commit() # 如果要对数据库进行操作,需要操作完以后进行commit提交
except:
conn.rollback() # 如果发生错误进行回滚,回到操作之前的状态
至于为啥要执行完操作要进行commit提交,后续我们会在事务里提到
我们再通过select语句查看是否插入数据成功
...省略连接
# 创建游标对象,用于操作数据库
cursor = conn.cursor()
cursor.execute('select * from student;')
data = cursor.fetchall()
print(data)
执行结果
((1, 'jack', 18), (2, 'tom', 19), (3, 'jams', 23), (4, 'rouse', 21), (5, 'mark', 25), (6, '张三', 26), (7, '李四', 29))
删除记录操作
通过SQL语句删除name为"张三"所在行的记录
# 创建游标对象,用于操作数据库
cursor = conn.cursor()
try: # 执行数据相关操作,最好放在try..except内执行,避免出现错误,导致数据出现问题
cursor.execute('delete from student where name = "张三";')
conn.commit()
except:
conn.rollback()
cursor.execute('select * from student;')
data = cursor.fetchall()
print(data)
执行结果
((1, 'jack', 18), (2, 'tom', 19), (3, 'jams', 23), (4, 'rouse', 21), (5, 'mark', 25), (7, '李四', 29))
更新数据操作
我们将通过update语句更新,将name字段为"李四"的年龄改成一个外部输入的内容
age = input('输入新的年龄:')
# 创建游标对象,用于操作数据库
cursor = conn.cursor()
sql = 'update student set age = %s where name = "李四";' % (age)
try: # 执行数据相关操作,最好放在try..except内执行,避免出现错误,导致数据出现问题
cursor.execute(sql)
conn.commit()
except:
conn.rollback()
cursor.execute('select * from student;')
data = cursor.fetchall()
print(data)
执行结果
输入新的年龄:35
((1, 'jack', 18), (2, 'tom', 19), (3, 'jams', 23), (4, 'rouse', 21), (5, 'mark', 25), (7, '李四', 35))
查询记录操作
PyMySQL提供给我们不同呈现记录的方式,元组、字典等。
此外它还提供给了我们3种不同形式的显示记录形式,因为PyMySQL查询是一种惰性机制,它会帮助我们节省内存空间,就是说内容不会立马返回给我们,而是存放在迭代器内,我们需要再进行返回,
- cursor.fetchall():显示迭代器内放置的所有记录
- cursor.fetchone():一次从迭代器内取出一条记录(相当于next)
- cursor.fetchmany(size):指定从迭代器内取出的记录数量,如果指定数量超过迭代器已存在的所有记录数量,则取所有的记录。
实例演示:cursor.fetchone()
# 创建游标对象,用于操作数据库
cursor = conn.cursor()
cursor.execute('select * from student;')
print(cursor.fetchone()) # 取出第一条记录
print(cursor.fetchone()) # 取出第二条记录
print(cursor.fetchone()) # 取出第三条记录
执行结果
(1, 'jack', 18)
(2, 'tom', 19)
(3, 'jams', 23)
实例演示:cursor.fetchmany(size)
# 创建游标对象,用于操作数据库
cursor = conn.cursor()
cursor.execute('select * from student;')
print(cursor.fetchmany(3))
执行结果
((1, 'jack', 18), (2, 'tom', 19), (3, 'jams', 23))
注意:将记录从迭代器内取出来以后,该记录就不会在存在于迭代器内。
# 创建游标对象,用于操作数据库
cursor = conn.cursor()
cursor.execute('select * from student;')
print(cursor.fetchmany(3))
print(cursor.fetchone()) # 取的是第四条记录,因为已经从迭代器内取走三条记录
执行结果
((1, 'jack', 18), (2, 'tom', 19), (3, 'jams', 23))
(4, 'rouse', 21)
简单说明SQL注入问题
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
下面简单演示SQL注入的产生
创建一个新的实验表:
create table login(
id int not null auto_increment primary key,
username varchar(30) not null,
password varchar(30) not null
);
insert login values(null,'admin','Admin0.0');
insert login values(null,'jack','101001');
insert login values(null,'tom','00000');
insert login values(null,'jams','111222..');
实验开始:
import pymysql
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
database='pymysql_test',
user='root',
password='password'
)
account = input('请输入账号:').strip()
password = input('请输入密码:').strip()
sql = 'select * from login where username = "%s" and password = "%s"' % (account,password)
cursor = conn.cursor()
cursor.execute(sql)
data = cursor.fetchall()
print(data)
接下来的关键点是:我们怎么添加额外的SQL语句,在提示我们输入account 或 password 时。在提示我们输入账号时,输入一下SQL语句
请输入账号:abc" or 1=1 -- a
请输入密码:直接回车
此时就会达到了SQL注入的效果,直接将整张表的内容给我们现实出来了
((1, 'admin', 'Admin0.0'), (2, 'jack', '101001'), (3, 'tom', '00000'), (4, 'jams', '111222..'))
在这里,如果我们要解决这个问题,有两种方案:
- 不让用户输入一些非法符号(通常网页就是这么操作的)
- 需要修改执行SQL语句的方式
account = input('请输入账号:').strip()
password = input('请输入密码:').strip()
sql = 'select * from login where username = "%s" and password = "%s"'
cursor = conn.cursor()
cursor.execute(sql,(account,password)) # 添加进入这里,PyMySQL会帮助我们判断处理
data = cursor.fetchall()
print(data)
执行结果
请输入账号:abc" or 1=1 -- a
请输入密码:
()
结果就是什么也没有显示出来,因为PyMySQL在这里帮助我们避开了这个问题,但是有些时候SQL注入的问题无法避免,其原因有一下:
- 广泛性
任何一个基于SQL语言的数据库都可能被攻击,很多开发人员在编写Web应用程序时未对从输入参数、Web表单、cookie等接受到的值进行规范性验证和检测,通常会出现SQL注入漏洞。 - 隐蔽性
SQL注入语句一般都嵌入在普通的HTTP请求中,很难与正常语句区分开,所以当前许多防火墙都无法识别予以警告,而且SQL注入变种极多,攻击者可以调整攻击的参数,所以使用传统的方法防御SQL注入效果非常不理想。 - 危害大
攻击者通过SQL注入获取到服务器的库名、表名、字段名,从而获取到整个服务器中的数据,对网站用户的数据安全有极大的威胁。攻击者也可以通过获取到的数据,得到后台管理员的密码,然后对网页页面进行恶意篡改。这样不仅对数据库信息安全造成严重威胁,对整个数据库系统安全也影响重大。 - 操作方便
互联网上有很多SQL注入工具,简单易学,攻击过程简单,不需要专业知识也能自如运用。
以上就是本文所表述的所有内容,希望本文能帮助到您对MySQL数据库理解。
技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请
点赞 收藏+关注
子夜期待您的关注,谢谢支持!