Python操作Mysql数据库

Python操作Mysql数据库

一,简介

Python 连接 MySQL 数据库是通过 MySQL 驱动程序实现的,常见的驱动有mysql-connector-pythonPyMySQL。以mysql-connector-python为例,它是 MySQL 官方提供的驱动,能让 Python 程序与 MySQL 数据库进行交互,实现数据的增删改查等操作。

优点

  1. 开源免费:MySQL 是开源数据库,Python 也是开源语言,使用成本低。
  2. 跨平台兼容:Python 和 MySQL 都支持多种操作系统,方便开发和部署。
  3. 高性能:MySQL 处理大量数据时性能优越,适合企业级应用。
  4. 丰富的驱动支持:有多个成熟的驱动可供选择,满足不同场景需求。
  5. 广泛的社区支持:遇到问题容易找到解决方案。

缺点

  1. 事务支持有限:虽然 InnoDB 存储引擎支持事务,但相比专业数据库如 Oracle,功能较弱。
  2. 复杂查询性能下降:对于复杂的关联查询,性能可能不如专业数据库。
  3. 安全机制较简单:MySQL 的安全机制相对简单,需要开发者自己加强安全措施。
  4. 驱动兼容性问题:不同版本的 MySQL 和驱动可能存在兼容性问题,需要注意版本匹配。

二,安装

1. 安装 MySQL 驱动程序

Python 连接 MySQL 8 最常用的驱动有两种,选择其一即可:

方法一:使用官方驱动 mysql-connector-python

这是 MySQL 官方提供的纯 Python 驱动,无需额外安装 C 库,兼容性好。

pip3 install mysql-connector-python
方法二:使用 PyMySQL

这是另一个流行的纯 Python 驱动,语法与 MySQLdb 兼容。

pip3 install pymysql

2. 可能需要的额外依赖

加密支持(可选)

如果 MySQL 服务器启用了强密码加密(如caching_sha2_password,MySQL 8 默认),可能需要安装:

pip3 install cryptography
  • 说明mysql-connector-pythonPyMySQL 通常会自动处理加密,但复杂场景下可能需要 cryptography 库。

总结

  • 必装mysql-connector-pythonPyMySQL
  • 可选cryptography(处理复杂加密场景)。

三,示例

我的库名testdb 里面两个表 users orders

python连接mysql并查看users表内的内容

import pymysql

# 建立数据库连接
db = pymysql.connect(
    host='192.168.10.101',  # 数据库服务器地址
    user='root',             # 数据库用户名
    password='pwd123',       # 数据库密码
    database='testdb'        # 要连接的数据库名
)

# 创建游标对象,用于执行SQL语句
cursor = db.cursor()

try:
    # 执行SQL查询语句,查询users表中的所有记录
    cursor.execute('SELECT * FROM users')
    
    # 获取查询结果集
    results = cursor.fetchall()
    
    # 遍历结果集并打印每一行数据
    for row in results:
        print(row)

except Exception as e:
    print(f"查询过程中发生错误: {e}")

finally:
    # 关闭游标,释放资源
    cursor.close()
    
    # 关闭数据库连接
    db.close()
代码说明:
  1. 数据库连接:通过pymysql.connect()方法创建数据库连接对象,需要提供主机地址、用户名、密码和数据库名。
  2. 游标操作:使用db.cursor()创建游标对象,该对象用于执行 SQL 语句并处理结果。
  3. SQL 执行:调用cursor.execute()方法执行 SQL 查询语句,这里查询的是users表的所有记录。
  4. 结果处理:使用cursor.fetchall()获取查询结果集,返回一个元组列表,每个元组代表一条记录。
  5. 资源释放:无论查询是否成功,最终都需要关闭游标和数据库连接,避免资源泄漏。
验证:
[root@localhost ~]# python3 a.py 
(1, 'Alice', 25)
(2, 'Bob', 30)
(3, 'Charlie', 35)
(4, 'David', 28)
!!!#成功

插入内容

import pymysql

# 建立数据库连接
db = pymysql.connect(
    host='192.168.10.101',  # 数据库服务器地址
    user='root',             # 数据库用户名
    password='pwd123',       # 数据库密码
    database='testdb'        # 要连接的数据库名
)

# 创建游标对象,用于执行SQL语句
cursor = db.cursor()

try:
    # 执行插入语句,使用参数化查询防止SQL注入
    # %s是pymysql的占位符,对应后面元组中的值
    cursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', ('zhangsan', 99))
    
    # 提交事务,将插入操作持久化到数据库
    db.commit()
    
    # 执行查询语句,查看插入后的结果
    cursor.execute('SELECT * FROM users')
    
    # 获取查询结果集
    results = cursor.fetchall()
    
    # 遍历结果集并打印每一行数据
    for row in results:
        print(row)

except Exception as e:
    # 发生异常时回滚事务
    db.rollback()
    print(f"操作过程中发生错误: {e}")

finally:
    # 关闭游标,释放资源
    cursor.close()
    
    # 关闭数据库连接
    db.close()
代码说明:
  1. 数据库连接:与之前相同,创建数据库连接对象。
  2. 插入操作
    • 使用cursor.execute()执行插入语句,通过参数化查询方式传递值
    • 参数化查询可有效防止 SQL 注入攻击
  3. 事务提交
    • 插入操作属于写操作,需要通过db.commit()提交事务
    • 如果不提交,数据不会真正写入数据库
  4. 查询验证
    • 插入后执行查询语句,验证数据是否成功插入
    • 结果集处理方式与之前相同
  5. 异常处理
    • 添加了db.rollback()在发生异常时回滚事务
    • 确保数据一致性
验证:
[root@localhost ~]# python3  a.py 
(1, 'Alice', 25)
(2, 'Bob', 30)
(3, 'Charlie', 35)
(4, 'David', 28)
(5, 'zhangsan', 99)

创建连接池

使用说明:
  1. 安装依赖
pip3 install DBUtils pymysql
  1. 连接池特点
    • 自动管理连接的创建和回收
    • 支持最小 / 最大连接数配置
    • 支持连接耗尽时的阻塞策略
    • 使用上下文管理器确保连接自动关闭
  2. 核心方法
    • get_connection():获取数据库连接
    • execute(sql, params):执行 SQL 语句,自动处理查询结果和事务
  3. 安全考虑
    • 所有 SQL 操作都使用参数化查询
    • 自动处理事务回滚
    • 支持字典格式的结果集
  4. 性能优化
    • 默认返回字典格式结果,便于处理
    • 连接可复用,减少开销
    • 支持连接池参数调优
代码
from dbutils.pooled_db import PooledDB
import pymysql

class MySQLPool:
    """MySQL数据库连接池类"""
    
    def __init__(self, host, user, password, database, 
                 mincached=1, maxcached=10, 
                 maxconnections=20, blocking=True):
        """
        初始化数据库连接池
        
        Args:
            host: 数据库主机地址
            user: 数据库用户名
            password: 数据库密码
            database: 数据库名
            mincached: 连接池中空闲连接的初始数量
            maxcached: 连接池中空闲连接的最大数量
            maxconnections: 允许的最大连接数
            blocking: 连接池达到最大连接数时是否阻塞
        """
        self.pool = PooledDB(
            creator=pymysql,  # 使用pymysql作为数据库驱动
            host=host,
            user=user,
            password=password,
            database=database,
            charset='utf8mb4',  # 支持中文和特殊字符
            cursorclass=pymysql.cursors.DictCursor,  # 返回字典格式的结果
            mincached=mincached,
            maxcached=maxcached,
            maxconnections=maxconnections,
            blocking=blocking
        )
    
    def get_connection(self):
        """从连接池获取一个连接"""
        return self.pool.connection()
    
    def execute(self, sql, params=None, commit=True):
        """执行SQL语句
        
        Args:
            sql: SQL语句
            params: SQL参数
            commit: 是否提交事务
            
        Returns:
            对于查询语句,返回结果列表;对于修改语句,返回受影响的行数
        """
        with self.get_connection() as conn:
            with conn.cursor() as cursor:
                try:
                    cursor.execute(sql, params or ())
                    if sql.strip().lower().startswith('select'):
                        return cursor.fetchall()
                    else:
                        if commit:
                            conn.commit()
                        return cursor.rowcount
                except Exception as e:
                    if commit:
                        conn.rollback()
                    raise e

# 使用示例
if __name__ == "__main__":
    # 创建连接池实例
    db_pool = MySQLPool(
        host='192.168.10.101',
        user='root',
        password='pwd123',
        database='testdb'
    )
    
    # 执行查询
    users = db_pool.execute("SELECT * FROM users WHERE age > %s", (25,))
    for user in users:
        print(user)
    
    # 执行插入
    result = db_pool.execute("INSERT INTO users (name, age) VALUES (%s, %s)", ("test", 30))
    print(f"插入成功,受影响行数: {result}")    

四,%s的含义

1. 为什么需要参数化查询?

直接拼接字符串会导致 SQL 注入风险。

例如:

# 危险!不要这样做!
name = "zhangsan'; DROP TABLE users; --"
query = f"SELECT * FROM users WHERE name = '{name}'"
cursor.execute(query)

恶意输入可能会破坏数据库。

2. %s 的作用

%s 告诉数据库驱动:“这里有一个动态值,需要安全地插入到 SQL 语句中”。驱动会自动处理转义和类型转换。

安全示例

name = "zhangsan"
cursor.execute("SELECT * FROM users WHERE name = %s", (name,))
  • 占位符%s 是值的占位符,无论值是什么类型。
  • 参数分离:实际值通过元组 (name,) 传递给 execute(),与 SQL 语句分离。

3. 如何使用 %s

单值查询
age = 25
cursor.execute("SELECT * FROM users WHERE age > %s", (age,))
多值插入
data = ("zhangsan", 25)
cursor.execute("INSERT INTO users (name, age) VALUES (%s, %s)", data)
批量插入
users = [("lisi", 30), ("wangwu", 35)]
cursor.executemany("INSERT INTO users (name, age) VALUES (%s, %s)", users)

4. 注意事项

  1. 仅用于值%s 只能替换值(如 WHERE name = %s),不能用于表名、列名等 SQL 关键字。
  2. 与 Python 字符串格式化的区别
    • Python 字符串格式化:"Hello %s" % name
    • SQL 参数化查询:"SELECT * FROM users WHERE name = %s"(语法相似,但用途不同)
  3. 不同数据库驱动的占位符
    • PyMySQL/mysql-connector:使用 %s
    • SQLite3:使用 ?(例如:WHERE name = ?)。
    • PostgreSQL (psycopg2):也使用 %s

5. 为什么 %s 更安全?

  • 自动转义:驱动会自动处理特殊字符(如引号),防止 SQL 注入。
  • 类型安全:无需手动处理引号(字符串会自动加引号,数字不会)。
  • 性能优化:预编译 SQL 语句,减少数据库解析开销。

五,事务管理

在 Python 中连接 MySQL 数据库时,事务管理是确保数据一致性和完整性的关键机制。下面我将详细解释如何管理事务,并提供示例代码。

一、事务的四大特性(ACID)

  1. 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败回滚。
  2. 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏。
  3. 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务。
  4. 持久性(Durability):事务一旦提交,其结果应该永久保存在数据库中。

二、Python 中管理 MySQL 事务的方法

1. 手动管理事务(基础方法)

使用 PyMySQL 连接时,默认自动提交(autocommit=True),需要手动关闭自动提交来管理事务:

import pymysql

# 建立数据库连接
conn = pymysql.connect(
    host='localhost',
    user='root',
    password='password',
    database='testdb'
)

try:
    # 关闭自动提交,开启事务
    conn.autocommit(False)
    cursor = conn.cursor()
    
    # 执行多个SQL操作
    cursor.execute("INSERT INTO users (name, age) VALUES (%s, %s)", ("Alice", 25))
    cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE user_id = 1")
    
    # 提交事务
    conn.commit()
    print("事务提交成功")

except Exception as e:
    # 发生异常时回滚事务
    conn.rollback()
    print(f"事务回滚: {e}")

finally:
    # 恢复自动提交模式并关闭连接
    conn.autocommit(True)
    conn.close()
2. 使用上下文管理器(推荐方法)

通过自定义上下文管理器,可以更优雅地管理事务:

import pymysql
from contextlib import contextmanager

# 创建数据库连接
def get_db_connection():
    return pymysql.connect(
        host='localhost',
        user='root',
        password='password',
        database='testdb'
    )

# 定义事务上下文管理器
@contextmanager
def transaction():
    conn = get_db_connection()
    conn.autocommit(False)
    
    try:
        yield conn  # 返回连接供外部使用
        conn.commit()  # 提交事务
    except Exception as e:
        conn.rollback()  # 回滚事务
        raise e
    finally:
        conn.autocommit(True)
        conn.close()

# 使用事务上下文管理器
with transaction() as conn:
    with conn.cursor() as cursor:
        cursor.execute("INSERT INTO users (name, age) VALUES (%s, %s)", ("Bob", 30))
        cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE user_id = 2")
3. 使用连接池管理事务(生产环境推荐)

使用DBUtils库创建连接池,并结合上下文管理器管理事务:

from dbutils.pooled_db import PooledDB
import pymysql
from contextlib import contextmanager

# 创建连接池
pool = PooledDB(
    creator=pymysql,
    host='localhost',
    user='root',
    password='password',
    database='testdb',
    mincached=2,
    maxcached=5
)

# 事务上下文管理器
@contextmanager
def transaction():
    conn = pool.connection()
    conn.autocommit(False)
    
    try:
        yield conn
        conn.commit()
    except Exception as e:
        conn.rollback()
        raise e
    finally:
        conn.autocommit(True)
        conn.close()

# 在事务中执行多个操作
with transaction() as conn:
    with conn.cursor() as cursor:
        # 转账操作:从账户1转100到账户2
        cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE user_id = 1")
        cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE user_id = 2")

三、事务隔离级别

MySQL 支持四种隔离级别,通过SET SESSION TRANSACTION ISOLATION LEVEL语句设置:

  1. READ UNCOMMITTED(读未提交):最低级别,可能读取到未提交的数据(脏读)。
  2. READ COMMITTED(读已提交):避免脏读,但可能出现不可重复读。
  3. REPEATABLE READ(可重复读):MySQL 默认级别,确保同一事务中多次读取结果一致。
  4. SERIALIZABLE(串行化):最高级别,强制事务串行执行,避免所有并发问题。

设置隔离级别示例

with conn.cursor() as cursor:
    cursor.execute("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")
    # 执行事务操作

四、关键要点总结

  1. 事务边界:明确事务的开始(关闭自动提交)和结束(提交或回滚)。
  2. 异常处理:必须捕获异常并回滚,确保事务的原子性。
  3. 资源管理:使用上下文管理器自动关闭连接和游标。
  4. 隔离级别:根据业务需求选择合适的隔离级别,避免脏读、幻读等问题。
  5. 连接池:生产环境中使用连接池提高性能,减少连接开销。

合理使用事务可以确保数据的一致性和完整性,特别是在涉及转账、库存管理等关键业务场景中尤为重要。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值