python sqlalchemy 案例

sqlalchemy案例

python 复制代码
from sqlalchemy import create_engine  # 创建连接的方法
from sqlalchemy import Table, Column, String, Integer, Text, MetaData  # 类
from sqlalchemy.engine import Engine  # 引擎类
from sqlalchemy import inspect, select, text  # 反射检查
from sqlalchemy.exc import IntegrityError  # 唯一键 索引等报错

"""
# 创建一次,全局共享(模拟 config 中的数据库配置)
# mysql+pymysql://用户:密码@主机:端口/数据库名
mysql是数据库方言,pymysql是数据库驱动协议
"""
engine: Engine = create_engine(
    "mysql+pymysql://root:root@127.0.0.1:3306/fastapi",
    pool_size=5,  # 连接池大小
    max_overflow=10,  # 超出 pool_size 后最多再创建 10 个连接
    pool_pre_ping=True,  # 每次从池取连接前先 ping 一下,避免拿到断开的连接
    echo=True,  # 设为 True 可打印所有 SQL,方便调试
)


def create_table(engine: Engine, request_table_name: str):
    """
    确保注册表存在(并发安全)。
    
    核心知识点:
      1. MetaData() ------ 表定义的容器,类似"建表清单"
      2. Table() ------ 在 Python 中定义一张表,不依赖已有数据库
      3. Column() ------ 定义列名 + 类型 + 约束
      4. meta.create_all() ------ 将 MetaData 中所有未创建的表创建到数据库
      5. inspect(engine) ------ 反射检查数据库已有表
      6. autoload_with=engine ------ 从已有数据库表反射出 Table 对象
    """
    """# ---- 知识点 1&2&3: 在 Python 中定义表结构 ----"""
    meta = MetaData()  # 表的容器

    """
    # Table()包裹表结构
    """
    table1 = Table(
        request_table_name, meta,  # 表名 + 所属表容器 Meta
        # 下面是字段定义
        Column("id", String(200), primary_key=True),  # 主键
        Column("comment", Text, nullable=False, comment="评论"),  # 文本类型 #必填,不可空
        Column("user_name", String(200), nullable=True),  # 非必填,可空
        Column("like_count", Integer, nullable=True),
    )

    """
        等价于
        CREATE TABLE t_book_comment (
        id VARCHAR(200) NOT NULL, 
        comment TEXT NOT NULL COMMENT '评论', 
        user_name VARCHAR(200), 
        like_count INTEGER, 
        PRIMARY KEY (id)
        )
    """

    """
    # ---- 知识点 5: inspect 反射检查 ----
    """
    inspector = inspect(engine)  # inspect,英文:检查
    exists = inspector.has_table(request_table_name)

    """
    # inspector 可以得到表信息、字段、索引等信息
    """

    print(f"表 {request_table_name} 是否存在: {exists}")  # 首次创建表之前返回False

    """
    # ---- 知识点 4: 自动建表 ----
    # create_all 是幂等的:只会创建不存在的表,已存在的表跳过
    # tables=[registry] 指定仅创建这张表,不创建 MetaData 中其他表
    """
    meta.create_all(engine, tables=[table1])

    """# ---- 知识点 5: inspect 反射检查 ----"""
    inspector = inspect(engine)
    exists = inspector.has_table(request_table_name)
    print(f"表 {request_table_name} 是否存在: {exists}")  # 创建完就存在了

    """
    # ---- 知识点 6: autoload_with 反射已有表 ----
    # 从数据库读出已有表结构,生成 Table 对象
    """
    meta_reflect = MetaData()
    """# 最新表信息"""
    latest_table_info = Table(request_table_name, meta_reflect, autoload_with=engine)
    """
    # 现在 registry_reflected 包含了数据库中的真实列信息
    # 手动增加列后,能拿到最新的列
    """
    print(
        f"反射得到的列名: {[c.name for c in latest_table_info.columns]}")  # 反射得到的列名: ['id', 'comment', 'user_name', 'like_count']


def queryById(engine: Engine, request_id: str, request_table_name: str):
    """
    查询注册表 ------ 使用 select() 构建查询。

    核心知识点:
      1. select() ------ SQLAlchemy 核心的 SELECT 构建方式
      2. table.c.column_name ------ 通过 .c 访问 Table 对象的列
      3. engine.connect() ------ 获取连接,用上下文管理器自动归还
      4. conn.execute() ------ 执行查询,返回 Result 对象
      5. .first() ------ 取第一条结果
    """

    """
    #meta = MetaData()
    # autoload_with 从数据库反射表结构
    #beQueryedTable = Table(request_table_name, meta, autoload_with=engine)
    # ---- 知识点 1&2: 构建 SELECT ----
    # 等价于: select comment from t_book_comment where id = 1 limit 1
    """
    # 下面这个完全可以
    query = text(f"select comment from t_book_comment where id = '{request_id}'")
    """
        # first()等同于.fetchone(),得到结果的第一个元组, result[0] 返回第一个元组中的一个元素
        # .fetchall() 能拿到所有记录,[(), (), ...]
        # result = conn.execute(query).fetchall() , result[0]是('张三的评论',) 元组
    """
    with engine.begin() as conn:
        result = conn.execute(query).first()
        """感觉这TM才好写啊,组装的恶心死了,而且还能用"""
        """# result = conn.execute(text("select comment from t_book_comment where id = 1")).first()"""
        return result[0] if result else None


"""# from datetime包 import datetime类"""
from datetime import datetime


def insertList(engine: Engine, request_table_name: str):
    """
       注册新表 ------ 使用 engine.begin() 自动事务 + 处理并发冲突。

       核心知识点:
         1. engine.begin() ------ 自动事务,exit 时自动 commit,异常时自动 rollback
         2. table.insert() ------ 构建 INSERT 语句
         3. conn.execute(statement) ------ 执行 INSERT
         4. IntegrityError ------ 捕获唯一键冲突(并发场景)
       """
    meta = MetaData()
    lastest_table_info = Table(request_table_name, meta, autoload_with=engine)

    now = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    print("当前时间:" + now)
    import uuid
    firstDataId = str(uuid.uuid4())
    dataDicList = [
        {"id": firstDataId, "comment": "李四的评论", "user_name": "李四", "like_count": 5},
        {"id": str(uuid.uuid4()), "comment": "王五的评论", "user_name": "王五", "like_count": 0},
        {"id": str(uuid.uuid4()), "comment": "这是一条很长的评论内容......", "user_name": "赵六", "like_count": 10},
        {"id": str(uuid.uuid4()), "comment": "测试评论", "user_name": None, "like_count": 1}
    ]
    try:
        with engine.begin() as conn:
            """
            # 单数据插入
            # {"id": "6", "comment": "测试评论", "user_name": None, "like_count": 1}
            """
            insert_stmt = lastest_table_info.insert().values(
                # 批量插入
                dataDicList
            )
            """# <class 'sqlalchemy.sql.dml.Insert'>"""
            print(type(insert_stmt))
            conn.execute(insert_stmt)
        return firstDataId
    except IntegrityError as e:
        print("唯一键冲突:" + str(e))


def update(engine: Engine, request_table_name: str, request_id: str):
    try:
        sql = text(f"update {request_table_name} set comment = '张三的评论' where id = '{request_id}'")
        with engine.begin() as conn:
            conn.execute(sql)
        return request_table_name
    except IntegrityError as e:
        """
        # ---- 知识点 4: 并发冲突处理 ----
        # 另一个进程已经插入了相同的 schema_key(唯一索引冲突)
        """

        """唯一键冲突:(pymysql.err.IntegrityError) (1062, "Duplicate entry '1' for key 'PRIMARY'")"""
        print("唯一键冲突:" + str(e))


def deleteById(engine: Engine, request_table_name: str, request_id: str):
    try:
        """
        # ---- 知识点 1: begin() 自动事务 ----
        # 进入 with 块时开启事务,离开时自动 commit
        # 如果抛出异常,自动 rollback
        """
        sql = text(f"delete from {request_table_name} where id = '{request_id}'")
        with engine.begin() as conn:
            # ---- 知识点 2&3: 构建并执行 INSERT ----
            conn.execute(sql)
        print("通过ID删除" + request_id)
        return request_table_name
    except Exception as e:
        print(str(e))


def dropTable(engine: Engine, request_table_name: str):
    try:
        """
        # ---- 知识点 1: begin() 自动事务 ----
        # 进入 with 块时开启事务,离开时自动 commit
        # 如果抛出异常,自动 rollback
        """
        sql = text(f"DROP TABLE IF EXISTS {request_table_name}")
        with engine.begin() as conn:
            conn.execute(sql)
        print("表:" + request_table_name + "被删除")
        return request_table_name
    except IntegrityError as e:
        """---- 知识点 4: 并发冲突处理"""
        """另一个进程已经插入了相同的 schema_key(唯一索引冲突)"""
        print("唯一键冲突:" + str(
            e))  # 唯一键冲突:(pymysql.err.IntegrityError) (1062, "Duplicate entry '1' for key 'PRIMARY'")


if __name__ == '__main__':
    dropTable(engine=engine, request_table_name="t_book_comment")

    """使用sqlalchemy创建表"""
    create_table(engine=engine, request_table_name="t_book_comment")

    firstDataId = insertList(engine=engine, request_table_name="t_book_comment")
    """    {"id": firstDataId, "comment": "李四的评论", "user_name": "李四", "like_count": 5} """
    res = queryById(engine, request_id=firstDataId, request_table_name="t_book_comment")
    """李四的评论"""
    print(res)

    update(engine=engine, request_table_name="t_book_comment", request_id=firstDataId)
    res = queryById(engine, request_id=firstDataId, request_table_name="t_book_comment")
    print(res)

    deleteById(engine=engine, request_table_name="t_book_comment", request_id=firstDataId)
相关推荐
名字还没想好☜1 小时前
Go 结构体内存对齐:调整字段顺序,同样的字段省下 40% 内存
开发语言·后端·golang·go·内存对齐
玛丽莲茼蒿1 小时前
很难出错的Spring5(十)—— IOC进阶
java·开发语言·jvm
Ulyanov1 小时前
雷达导引头仿真中的坐标系——从惯性系到量测角
开发语言·python·算法·系统仿真·雷达信号处理·雷达导引头
codeboss1 小时前
做网页变更监控,我在“降噪”上踩过的 7 个坑
爬虫·python
果汁华2 小时前
CLI 命令行与 Python 框架实战
git·python·github
Maiko Star2 小时前
FastAPI 进阶三部曲:中间件、依赖注入与 ORM 实战
python·中间件·fastapi
MrDJun2 小时前
长期稳定跑网页监控:TLS 指纹、代理选路与请求节流的工程实践
运维·爬虫·python·网络协议·网站监控
m沐沐2 小时前
【计算机视觉】OpenCV 物体跟踪——原理、算法与CSRT跟踪器实战
人工智能·python·深度学习·opencv·算法·计算机视觉·人脸识别
前鼻音太阳熊2 小时前
【MES系统】- 工业HMI状态机可视化实践:从手写SVG到Cytoscape.js的技术选型与踩坑
开发语言·javascript·ecmascript