十五Python 操作 MySQL 数据库------非ORM

Posted Amo Xiang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了十五Python 操作 MySQL 数据库------非ORM相关的知识,希望对你有一定的参考价值。

文章目录

前置知识:

一、数据库开发与实战专栏导学及数据库基础概念入门
二、MySQL 介绍及 MySQL 安装与配置
三、MySQL 数据库的基本操作
四、MySQL 存储引擎及数据类型
五、数据导入与基本的 SELECT 语句
六、MySQL 数据库练习题1(包含前5章练习题目及答案)
七、MySQL 多表查询详解(附练习题及答案----超详细)
八、MySQL 常用函数汇总(1)
九、MySQL 常用函数汇总(2)
十、MySQL 聚合函数、分组查询及过滤分组
十一、子查询详解
十二、创建和管理表
十三、表数据的增、删、改操作
十四、MySQL 约束详解

一、mysql 官方驱动模块 — MySQL Connector

MySQL ConnectorMySQL 官方的驱动模块,兼容性特别好。官方地址: https://dev.mysql.com/downloads/connector/python/ Windows 下载安装即可,Linux 系统下载 RPM 安装包,也可以使用 pip 进行安装,命令如下:

# Linux 系统下我使用的python版本是python3.8
pip3/pip install mysql-connector-python

1.1 连接数据库

# -*- coding: utf-8 -*-
# @Time    : 2023-02-22 23:10
# @Author  : AmoXiang
# @File    : demo1.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680


import mysql.connector

# 第一种连接方式
# conn = mysql.connector.connect(host="127.0.0.1", port=3306, user="root",
#                                password="123456", database="mysql_study")
# conn.close()


# 第二种连接方式: 使用配置的方式连接
config = 
    "host": "127.0.0.1",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "mysql_study",

conn = mysql.connector.connect(**config)
# 查询数据
sql = "SELECT grade_level,lowest_sal,highest_sal FROM job_grades;"
# 游标(Cursor): MySQL Connector里面的游标用来执行SQL语句,而且查询的结果集也会保存在游标之中
cursor = conn.cursor()
cursor.execute(sql)
for row in cursor:
    print(row[0], row[1], row[2])
conn.close()

1.2 实战:SQL注入攻击案例

由于 SQL 语句是解释型语言,所以在拼接 SQL 语句的时候,容易被注入恶意的 SQL 语句,示例如下:

# -*- coding: utf-8 -*-
# @Time    : 2023-02-23 6:10
# @Author  : AmoXiang
# @File    : demo2.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680

import mysql.connector

# 连接
config = 
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "mysql_study"


conn = mysql.connector.connect(**config)
cursor = conn.cursor()
# SQL 语句
username = "1 OR 1=1"
password = "1 OR 1=1"
# SQL 拼接的第一种方式
sql1 = "SELECT COUNT(*) FROM t_user WHERE username=" + username + \\
       " AND AES_DECRYPT(UNHEX(password),'HelloWorld')=" + password + ";"
# print(sql1)
# cursor.execute(sql1)
# print(cursor.fetchone()[0])
# SQL 拼接使用格式化字符串
sql2 = f"SELECT COUNT(*) FROM t_user WHERE username=username AND " \\
       f"AES_DECRYPT(UNHEX(password),'HelloWorld')=password;"
print(sql2)
cursor.execute(sql2)
print(cursor.fetchone()[0])
# 注意: 使用该种sql拼接不会引起sql注入
sql3 = f"SELECT COUNT(*) FROM t_user WHERE username='username' AND " \\
       f"AES_DECRYPT(UNHEX(password),'HelloWorld')='password';"

conn.close()

解决方案:

# -*- coding: utf-8 -*-
# @Time    : 2023-02-23 6:10
# @Author  : AmoXiang
# @File    : demo2.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680

import mysql.connector

# 连接
config = 
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "mysql_study"


conn = mysql.connector.connect(**config)
cursor = conn.cursor()
# SQL 语句
username = "1 OR 1=1"
password = "1 OR 1=1"
# 使用%s占位符
sql = "SELECT COUNT(*) FROM t_user WHERE username=%s AND AES_DECRYPT(UNHEX(password),'HelloWorld')=%s;"
print(sql)
# execute 第二个参数为元组 如果只传入一个值 别忘记加, 例如(username,)
# 预编译SQL就是数据库提前把SQL语句编译成二进制,这样反复执行同一条SQL语句的效率就会提升
# SQL语句编译的过程中,关键字已经被解析过了,所以向编译后的SQL语句传入参数,都被当做字符串处理,
# 数据库不会解析其中注入的SQL语句
cursor.execute(sql, (username, password))
print(cursor.fetchone()[0])
conn.close()

1.3 MySQL Connector 的事务及异常处理

事务控制: Connector 为我们提供了非常简单的事务控制函数。

# -*- coding: utf-8 -*-
# @Time    : 2023-02-23 7:00
# @Author  : AmoXiang
# @File    : demo3.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680

import mysql.connector

# 连接
config = 
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "mysql_study"

try:
    conn = mysql.connector.connect(**config)
    conn.start_transaction()  # 开启事务
    cursor = conn.cursor()
    # SQL 语句 使用%s占位符
    sql = "INSERT INTO dept(did,dname) VALUES(%s,%s);"
    print(sql)
    cursor.execute(sql, (1005, "人事部"))  # 无返回值
    # 提交事务
    conn.commit()
except Exception as e:
    print(e)
    if "conn" in dir():
        conn.rollback()
finally:
    if "conn" in dir():
        conn.close()

1.4 数据库连接池技术

数据库连接的昂贵之处: 数据库连接是一种关键的、有限的、昂贵的资源,在并发执行的应用程序中体现得尤为突出。TCP 连接需要三次握手,四次挥手,然后数据库还要验证用户信息。

数据库连接池的意义: 数据库连接池( Connection Pool) 预先创建出一些数据库连接然后缓存起来,避免了程序语言反复创建和销毁连接昂贵代价。

示例如下:

# -*- coding: utf-8 -*-
# @Time    : 2023-02-23 7:20
# @Author  : AmoXiang
# @File    : demo4.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680

import mysql.connector.pooling

# 连接
config = 
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "mysql_study"

try:
    pool = mysql.connector.pooling.MySQLConnectionPool(**config, pool_size=10)
    # 从连接池中取出链接
    conn = pool.get_connection()
    conn.start_transaction()  # 开启事务
    cursor = conn.cursor()
    # SQL 语句 使用%s占位符
    sql = "UPDATE dept SET did=%s  WHERE dname=%s;"
    print(sql)
    cursor.execute(sql, (1006, "人事部"))  # 无返回值
    # 提交事务
    conn.commit()
except Exception as e:
    print(e)
    if "conn" in dir():
        conn.rollback()

1.5 MySQL Connector 删除数据

# -*- coding: utf-8 -*-
# @Time    : 2023-02-26 3:05
# @Author  : AmoXiang
# @File    : demo5.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680

import mysql.connector

# 数据库连接配置
config = 
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "mysql_study"


try:
    pool = mysql.connector.pooling.MySQLConnectionPool(**config, pool_size=10)
    # 从连接池中取出连接
    conn = pool.get_connection()

    # TODO 1. 使用delete from 删除表中数据
    # conn.start_transaction()  # 开启事务
    # cursor = conn.cursor()
    # 删除表中数据
    # sql = "DELETE e,d FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno WHERE d.deptno=20;"
    # cursor.execute(sql)
    # conn.commit()

    # TODO 2. 使用 truncate table 清空表 不用开启事务与提交事务
    cursor = conn.cursor()
    sql = "TRUNCATE TABLE t_emp;"
    cursor.execute(sql)
except Exception as e:
    if "conn" in dir():
        conn.rollback()
    print(e)

1.6 MySQL Connector 多条数据插入

循环执行 SQL 语句: 游标对象中的 executemany() 函数可以反复执行一条 SQL 语句。

# -*- coding: utf-8 -*-
# @Time    : 2023-02-26 3:30
# @Author  : AmoXiang
# @File    : demo6.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680

import mysql.connector.pooling

# 数据库连接配置
config = 
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "mysql_study"


try:
    pool = mysql.connector.pooling.MySQLConnectionPool(**config, pool_size=10)
    con = pool.get_connection()
    con.start_transaction()  # 开启事务
    cursor = con.cursor()
    sql = "INSERT INTO t_dept(deptno,dname,loc) VALUES(%s,%s,%s);"
    data = [
        [100, "A部门", "北京"],
        [110, "B部门", "上海"],
    ]
    cursor.executemany(sql, data)
    con.commit()
except Exception as e:
    if "con" in dir():
        con.rollback()
    print(e)

1.7 案例练习

1.7.1 练习一

使用 INSERT 语句把所在部门平均工资超过公司平均工资的员工信息导入到 t_emp_new 表里面,并且让这些员工隶属于 sales 部门。

# -*- coding: utf-8 -*-
# @Time    : 2023-03-03 6:59
# @Author  : AmoXiang
# @File    : demo7.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680

import mysql.connector.pooling

"""
使用 INSERT 语句把所在部门平均工资超过公司平均工资的员工信息导入到 t_emp_new 表里面,并且让这些员工隶属于 sales 部门。
在 Python 程序中与SQL语句:将复杂的SQL语句拆分成简单的SQL语句进行执行,并将其查询的结果保存在变量中,得以复用。
"""

# 数据库连接配置
config = 
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "mysql_study"


try:
    pool = mysql.connector.pooling.MySQLConnectionPool(**config, pool_size=10)
    conn = pool.get_connection()
    # 开启事务
    conn.start_transaction()
    cursor = conn.cursor()
    # 创建表
    sql = "CREATE TABLE IF NOT EXISTS t_emp_new LIKE t_emp;"
    cursor.execute(sql)
    # 查询出公司的平均工资
    sql = "SELECT AVG(sal) AS avg FROM t_emp;"
    cursor.execute(sql)
    temp = cursor.fetchone()
    avg = temp[0]
    print(avg)
    # 查询出部门平均工资
    sql = "SELECT deptno FROM t_emp GROUP BY deptno HAVING AVG(sal)>=%s;"
    cursor.execute(sql, [avg])
    temp = cursor.fetchall()
    zw_chr = ('%s, ' * len(temp)).strip()[:-1]
    # 插入数据
    sql = "INSERT INTO t_emp_new SELECT * FROM t_emp WHERE deptno IN(" + zw_chr + ")"
    cursor.execute(sql, [_[0] for _ in temp])
    print(sql)
    # 删除原表中的数据
    sql = "DELETE FROM t_emp WHERE deptno IN(" + zw_chr + ")"
    cursor.execute(sql, [_[0] for _ in temp])
    # 新表中的部门改为 "SALES"
    sql = "SELECT deptno FROM t_dept WHERE dname=%s;"
    cursor.execute(sql, ["SALES"])
    sales_deptno = cursor.fetchone()[0]  # 注意fetchone返回的是一个元组 要使用索引取出第1个元素
    sql = "UPDATE t_emp_new SET deptno=%s;"
    cursor.execute(sql, [sales_deptno])
    conn.commit()
except Exception as e:
    if "conn" in dir():
        conn.rollback()
    print(e)

1.7.2 练习2

编写一个 INSERT 语句向部门表插入两条记录,每条记录都在部门原有最大主键值的基础上 +10

# -*- coding: utf-8 -*-
# @Time    : 2023-03-03 8:14
# @Author  : AmoXiang
# @File    : demo8.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680

import mysql.connector.pooling

"""
编写一个 INSERT 语句向部门表插入两条记录,每条记录都在部门原有最大主键值的基础上 +10
"""

# 数据库连接配置
config = 
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "mysql_study"


try:
    pool = mysql.connector.pooling.MySQLConnectionPool(**config, pool_size=10)
    conn = pool.get_connection()
    # 开启事务
    conn.start_transaction()
    cursor = conn.cursor()
    sql = """INSERT INTO t_dept SELECT MAX(deptno)+10, %s, %s FROM t_dept
             UNION  SELECT MAX(deptno)+20, %s, %s FROM t_dept;"""
    cursor.execute(sql, ["A部门", "上海", "B部门", "北京"])
    conn.commit()
except Exception as e:
    if "conn" in dir():
        conn.rollback()
    print(e)

二、PyMySQL 操作数据库

Python 中使用 MySQL 建议使用的客户端库是 PyMySQL,跨平台性、兼容性更好。在开始之前,请确保已经安装好了 MySQL 数据库并且保证能够正常运行。此外还需要安装 PyMySQL 库:安装方法非常简单,执行如下命令即可:

pip install -i http://pypi.douban.com/simple --trusted-host pypi.douban.com PyMysql

2.1 连接数据库

# -*- coding: utf-8 -*-
# @Time    : 2023-03-09 12:55
# @Author  : AmoXiang
# @File    : 1.连接数据库.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680

from pymysql import connect, Error

"""
使用pymysql连接数据库
"""

# 数据库的连接对象
conn = None
try:
    # 建立连接
    conn = connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='',
        database='my_data_base'
    )
    print(conn)
    conn.close()
except Error as e:
    print('连接失败:'.format(e))
finally:
    try:
        # 关闭连接
        conn.close()
        print('数据库连接已关闭')
    except Exception as e:
        print('数据库连接关闭失败:'.format(e))

此外,connect() 函数还有两个常用参数设置,介绍如下:

  1. charset: utf8 用于设置 MySQL 字符集为 UTF-8
  2. cursorclass: pymysql.cursors.DictCursor 用于设置游标类型为字典类型,默认为元组类型。

2.2 PyMySQL 的基本使用

操作 MySQL 的基本流程为:连接 MySQL → 创建游标 → 执行 SQL 语句 → 关闭连接。

【示例1】连接数据库:

import pymysql
from pymysql import Error

try:
    """
    host:MySQL运行的host 即ip 本地localhost MySQL 在远程传入公网ip即可
    user: 用户名
    password: 密码
    port: 端口
    """
    db = pymysql.connect(host="localhost", user="root", password="123456", port=3306)
    cursor = db.cursor()
    cursor.execute("SELECT VERSION();")
    data = cursor.fetchone()
    print(f"Database version: data")  # Database version: ('8.0.30',)
    cursor.execute("CREATE DATABASE spiders DEFAULT CHARACTER SET utf8mb4;")
    db.close()
except Error as e:
    if "db" in dir():
        db.rollback()
    print(e)
finally:
    if "db" in dir():
        db.close()

【示例2】创建表:

# -*- coding: utf-8 -*-
# @Time    : 2023-03-09 13:14
# @Author  : AmoXiang
# @File    : 3.创建表.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680

import pymysql

# 创建数据库后,需要指定在哪个数据库下进行操作 db: 数据库
db = pymysql.connect(host="localhost", user="root", password="123456", port=3306, db="spiders")
cursor = db.cursor()
sql = 'CREATE TABLE IF NOT EXISTS students(id VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, age INT NOT NULL, ' \\
      'PRIMARY KEY(id))'

cursor.execute(sql)
db.close()

【示例3】插入数据----初版。

# -*- coding: utf-8 -*-
# @Time    : 2023-03-09 13:15
# @Author  : AmoXiang
# @File    : 4.插入数据-初版.py
# @Software: PyCharm
# @Blog    : https://blog.csdn.net/xw1680

import pymysql

s_id = "20140041"
user = "Amo"
age = 18

db = pymysql.connect(host="localhost", user="root", password="123456", port=3306, db="spiders")
cursor = db.cursor()
sql = 'INSERT INTO students(id, name, age) VALUES(%s, %s, %s);'
try:
    cursor.execute(sql, (s_id, user, age))
    db以上是关于十五Python 操作 MySQL 数据库------非ORM的主要内容,如果未能解决你的问题,请参考以下文章

Linux学习总结(四十五)mysql 基本操作 上篇

Python学习第二十五课——Mysql (多表查询)

Java基础学习笔记二十五 MySQL

Java学习总结(十五)——MySQL数据库(上)—增,删,改与部分查询语句

Python其实很简单 第十五章 文件操作

树莓派开发笔记(十五):树莓派4B+从源码编译安装mysql数据库