Python与MySQL交互:MySQL Connector模块(七)

本文介绍了MySQLConnector作为MySQL官方Python驱动的使用方法,包括如何创建连接、操作游标、预编译SQL以防止SQL注入、控制事务、处理异常以及利用数据库连接池。同时,展示了CRUD操作和两个案例,强调了在实际操作中的安全性与效率。
摘要由CSDN通过智能技术生成

MySQL Connector模块

MySQL Connector是MySQL官方的驱动模块,兼容性好

[下载地址](MySQL :: Download MySQL Connector/Python (Archived Versions))

命令行直接安装:pip install mysql-connector-python

1 创建连接

方式一:

import mysql.connector

con = mysql.connector.connect(
    host="localhost", port="3306",
    user="root", password="123456",
    database="study"
)

方式二:

import mysql.connector

config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "vaga"
}
con = mysql.connector.connect(**config)

2 游标

MySQL Connector里面的游标(Cursor)用来执行SQL语句,而且查询的结果集也会保存在游标之中。

# 创建游标
# params可以是元组,列表,字典
cursor=con.cursor()
cursor.execute(sql_query, params)
# params_list是一个包含参数值的列表的列表或元组的列表, %s为占位符,防止SQL注入攻击
cursor.executemany(sql_query, params_list)

例1:

import mysql.connector

con = mysql.connector.connect(
    host="localhost", port="3306",
    user="root", password="123456",
    database="study"
)

# 创建游标
cursor=con.cursor()
sql = "select empno, ename, hiredate from t_emp;"
cursor.execute(sql)

for one in cursor:
    print(one[0], one[1], one[2])

con.close()

例2:

cursor = con.cursor()
sql = "insert into t_dept(deptno, dname, loc) values (%s, %s, %s);"
data=[
    [100, "A部门", "北京"],
    [110, "B部门", "上海"]
]
cursor.executemany(sql, data)

3 预编译SQL

SQL注入攻击: 由于SQL语句是解释型语言,所以在拼接SQL语句的时候,容易被注入恶心的SQL语句。

例如:一旦执行sql该语句就会执行,说白了,是用户输入恶意信息对数据库进行操作。

id = "1 OR 1=1"
sql = "DELETE FROM t_news WHERE id="+id

为防止SQL注入攻击可采用预编译机制

预编译机制:

在这里插入图片描述

SQL预编译机制抵御注入攻击: SQL语句编译的过程中,关键字 已经被解析过了,所以向编译后的SQL语句传入参数,都被当做字符串处理,数据库不会解析其中注入的SQL语句。

例子:

import mysql.connector

config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "vaga"
}
con = mysql.connector.connect(**config)
username="1 OR 1=1"
password="1 OR 1=1"

sql = "select count(*) from t_user where username=%s " \
      " and aes_decrypt(unhex(password), 'HelloWorld')=%s;"

cursor = con.cursor()

# 让sql先编译,然后再传递给它值,防止注入攻击
cursor.execute(sql, (username, password))

print(cursor.fetchone()[0])
con.close()

4 事务控制

Connector提供了事务控制函数

开启事务: con.start_transaction([事务的隔离级别])

提交事务:con.commit()

回滚事务:con.rollback()

其中con为数据库连接对象

5 异常处理

import mysql.connector

try:
    con = mysql.connector.connect(
        host="localhost",
        port=3306,
        user="root",
        password="123456",
        database="study"
    )
    cursor = con.cursor()
    sql = "insert into t_emp(empno, ename, job, mgr, hiredate, sal, comm, deptno)" \
          "values (%s, %s, %s, %s, %s, %s, %s, %s)"
    cursor.execute(sql, (9600, "赵娜", "SALESMAN", None, "1985-12-1", 2500, None, 10))
    con.commit()
except Exception as e:
    if "con" in dir():
        con.rollback()
    print(e)
finally:
    # 检查当前命名空间中是否存在名为 con 的变量或对象
    if "con" in dir():
        con.close()

6 数据库连接池

数据库连接的昂贵之处: 数据库连接是一种关键的、有限的、昂贵的资源,在并发执行的应用程序中体现的尤为突出。

TCP连接需要三次握手,四次挥手,然后数据库还要验证用户信息

TCP建立连接的时候会占用线程,有等待时间,浪费线程资源,硬件开销和时间成本高

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

启用数据库连接池后不用关闭数据库连接,连接池会自动回收

例子:

import mysql.connector.pooling

config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "study"
}
try:
    # 创建连接池
    pool=mysql.connector.pooling.MySQLConnectionPool(
        **config,       # 连接的数据库
        pool_size=10    # 连接池的大小
    )
    con = pool.get_connection()     # 获取连接池中的一个连接
    con.start_transaction()         # 开启事务
    cursor = con.cursor()           # 获取游标
    sql = "update t_emp set sal=sal+%s where deptno=%s"
    cursor.execute(sql, (200, 20))  # 执行sql
    con.commit()
except Exception as e:
    if "con" in dir():
        con.rollback()
    print(e)

7 CRUD操作

增加:

import mysql.connector.pooling

config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "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)

读取:

import mysql.connector

config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "vaga"
}
con = mysql.connector.connect(**config)
username="1 OR 1=1"
password="1 OR 1=1"

sql = "select count(*) from t_user where username=%s " \
      " and aes_decrypt(unhex(password), 'HelloWorld')=%s;"

cursor = con.cursor()

# 让sql先编译,然后再传递给它值,防止注入攻击
cursor.execute(sql, (username, password))

print(cursor.fetchone()[0])
con.close()

修改:

import mysql.connector.pooling

config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "study"
}
try:
    # 创建连接池
    pool=mysql.connector.pooling.MySQLConnectionPool(
        **config,       # 连接的数据库
        pool_size=10    # 连接池的大小
    )
    con = pool.get_connection()     # 获取连接池中的一个连接
    con.start_transaction()         # 开启事务
    cursor = con.cursor()           # 获取游标
    sql = "update t_emp set sal=sal+%s where deptno=%s"
    cursor.execute(sql, (200, 20))  # 执行sql
    con.commit()
except Exception as e:
    if "con" in dir():
        con.rollback()
    print(e)

删除:

import mysql.connector.pooling

config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "study"
}

try:
    pool = mysql.connector.pooling.MySQLConnectionPool(
        **config,
        pool_size=10
    )
    con = pool.get_connection()
    # con.start_transaction()
    cursor = con.cursor()
    # sql = "delete e,d from t_emp e join t_dept d on e.deptno=d.deptno where d.deptno=20;"
    # truncate不依赖于事务
    sql = "truncate table t_emp;"
    cursor.execute(sql)
    # con.commit()
except Exception as e:
    if "con" in dir():
        con.rollback()
    print(e)

8 案例1

题目: 使用insert语句,把部门平均底薪超过公司平均底薪的这样的部门里的员工信息导入到t_emp_new表里面,并且让这些员工隶属于SALES部门

import mysql.connector.pooling

config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "study"
}

try:
    pool = mysql.connector.pooling.MySQLConnectionPool(
        **config,
        pool_size=10
    )
    con = pool.get_connection()
    con.start_transaction()
    cursor = con.cursor()
    # 数据表的结构来自于查询,用t_emp的表结构
    # ddl语句和事务管理没关系
    '''
    create table t_emp_new as (select * from t_emp);
    创建新表并将复制t_emp表中的信息,表结构和数据
    create table t_emp_new like t_emp;
    创建t_emp_new表,表结构是t_emp的表结构,无数据
    '''
    # sql = "create table t_emp_new as (select * from t_emp);"

    sql = "drop table t_emp_new;"
    cursor.execute(sql)
    sql = "create table 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]  # 公司平均底薪
    sql = "select deptno from t_emp group by deptno having avg(sal)>=%s;"
    cursor.execute(sql, [avg])
    # 取出结果集
    temp = cursor.fetchall()

    # 向新表插入数据
    sql = "insert into t_emp_new select * from t_emp where deptno in ("
    for index in range(len(temp)):
        one = temp[index][0]
        if index < len(temp) - 1:
            sql += str(one) + ","
        else:
            sql += str(one)
    sql += ")"
    cursor.execute(sql)

    # 删除旧表的数据
    sql = "delete from t_emp where deptno in ("
    for index in range(len(temp)):
        one = temp[index][0]
        if index < len(temp) - 1:
            sql += str(one) + ","
        else:
            sql += str(one)
    sql += ")"
    cursor.execute(sql)

    # 让这些员工隶属于sales部门
    sql = "select deptno from t_dept where dname=%s"
    cursor.execute(sql, ["SALES"])
    deptno = cursor.fetchone()[0]
    sql = "update t_emp_new set deptno=%s"
    cursor.execute(sql, [deptno])

    con.commit()
except Exception as e:
    if "con" in dir():
        con.rollback()
    print(e)

9 案例2

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

import mysql.connector.pooling

config = {
    "host": "localhost",
    "port": 3306,
    "user": "root",
    "password": "123456",
    "database": "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 (select max(deptno)+10, %s, %s from t_dept UNION" \
          "(select max(deptno)+20, %s, %s from t_dept))"
    cursor.execute(sql, ("A部门", "北京", "B部门", "上海"))
    con.commit()

except Exception as e:
    if "con" in dir():
        con.rollback()
    print(e)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值