SqlAlchemy使用教程(二) 入门示例及通过CoreAPI访问与操作数据库

在这里插入图片描述

二、入门示例与基本编程步骤

在第一章中提到,Sqlalchemy提供了两套方法来访问数据库,由于Sqlalchemy 文档杂乱,对于ORM的使用步骤讲解杂乱,SqlAlchemy2.x 与j1.x版本差异也较大,很多介绍SqlAlchemy的文章上来就讲ORM,但又混杂着CoreAPI,常令初学者遇到各种问题。因此,本人建议先使用Core API来访问数据库,使用上更接近于 Sqlite3, Mysql-connector 等的方式,入门容易,而且也可以实现1套代码支持各类数据库。
因此,本教程开头3章均以Core API方式为主。

1、DB API访问数据库入门示例

示例功能:

  • 建立数据库连接
  • 通过Core API访问数据库(创建表,插入数据,查询数据)

1.1建立数据库连接

Step-1: 创建数据库引擎对象
DB Engine 是个全局变量,允许在其上建立多个connection访问数据库。

创建 DB Engine 实例的方法:
create_engine( db_url )
db_url参数在后面章节中详解介绍。本例使用sqlite3 内存数据库。

from sqlalchemy import create_engine
engine = create_engine("sqlite:///:memory:", echo=True)

Step-2 创建connect对象
connection 对象用于数据库操作。其支持context with语法

from sqlalchemy import text
with engine.connect() as conn:result = conn.execute(text("select 'hello world'"))print(result.all())

output

[('hello world',)]

Step-3 执行SQL Express 语句
text() 是SQL express 的最简单使用形式, 方便传值

创建1张表

conn.execute(text("CREATE TABLE some_table (x int, y int)"))

插入数据,

conn.execute(text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),[ { "x": 1, "y": 1}, {"x": 2, "y": 4 } ],)

SQL express传参语法:

  • 参数占位使用 :x, :y , 参数名前加:分号
  • 实际值用 [ dict, … ] 方式给出。

提交事务, 即将操作保存至数据库

conn.commit()

Step4 执行查询并获取结果

with engine.connect() as conn:result = conn.execute(text("SELECT x, y FROM some_table"))for row in result:print(f"x: {row.x}  y: {row.y}")

本例中,select x,y from some_table 将返回所有行

返回结果类型为 sqlalchemy.engine.cursor.CursorResult,是1个由 object 组成的可迭代对象。提供了多种方法访问结果数据:

  • fetchall(), fetchone(), fetchmany() ,使用tuple方式读取全部、单条、多条数据
  • all() 获取所有数据,返回列表
  • mappings(), 返回列表,元素为dict类型,
  • keys() 获取对象属性名(字段名)

还可以向查询语句传参:

result = conn.execute(text("SELECT x, y FROM some_table WHERE y > :y"), {"y": 2})

2、SqlAlchemy 异常处理

编写代码时1个好习惯:先写出异常与错误处理语句框架,再写正常流程部分,这样的习惯可以让代码更健壮,避免程序运行中断或出错。

虽然看似麻烦,但最终代码测试中遇到的问题更少,而且错误日志也更精准,问题定位效率更高,所以这样做将更省时间。

2.1 异常处理代码结构建议

from sqlalchemy import create_engine
from sqlalchemy.exc import IntegrityError, ProgrammingErrorengine = create_engine('mysql://username:password@localhost/mydatabase')try:# 执行数据库操作connection = engine.connect()# ...# 这里是可能引发异常的代码# ...connection.close()
except IntegrityError as e:# 处理唯一性约束违反等完整性错误print(f'Integrity error occurred: {str(e)}')
except ProgrammingError as e:# 处理SQL语法或参数错误print(f'Programming error occurred: {str(e)}')
except SQLAlchemyError as e:# 处理其他SQLAlchemy异常print(f'An error occurred: {str(e)}')

2.2 SQLAlchemy常用的内置异常类

  • sqlalchemy.exc.SQLAlchemyError:所有SQLAlchemy异常的基类
  • sqlalchemy.exc.InvalidRequestError:无效的请求异常,包括无效的查询或表达式
  • sqlalchemy.exc.StatementError:执行SQL语句时出错的异常
  • sqlalchemy.exc.IntegrityError:完整性约束错误,例如唯一性约束或外键约束违反等
  • sqlalchemy.exc.OperationalError:操作数据库时出错的异常
  • sqlalchemy.exc.ProgrammingError:编程错误,例如错误的SQL语法或参数错误等

三、使用Core DB API(重点)

1、创建DB engine 对象

1.1创建database engine 对象

Engine 是db连接管理类,
语法:

from sqlalchemy import create_engine
#创建引擎对象
engine = create_engine("sqlite:///:memory:", echo=True)
#连接数据库
conn = engine.connect()

Sqlalchemy.create_engine( ) 方法第1个参数是db连接表达式,格式为:

dialect[+driver]://user:password@host/dbname
  • dialect 通常为数据库类型,如sqlite, mysql, mongodb, etc.
  • driver 是python 访问数据库的包。
    如 sqlite+sqlite3, mysql+mysqlconnector

1.2 连接至各类数据库的配置

1.2.1 sqlite 连接

上面示例是sqlite的连接表达式。 Driver是python访问数据库的DBAPI库。

e = create_engine('sqlite:///path/to/database.db')

如果是绝对地址 sqlite:usr/local/myproject/database.db

:memory 表示使用内存数据库,不保存在硬盘。
对于windows 系统,

e = create_engine('sqlite:///C:\\myapp\\db\\main.db')
1.2.2 连接mysql

Mysql 的DBAPI,常用的有PyMysql 与 mysql-connector,其连接表达式分别为:

mysql+pymysql://root:123456@192.168.99.240:3306/testdb
mysql+mysqlconnector://roprot:123456@192.168.99.240:3306/testdb
1.2.3 连接PostgreSQL

通常使用的接口库为 psycopg2

postgresql+psycopg2://user:password@host:port/dbname[?key=value&key=value...]engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test",isolation_level="SERIALIZABLE",
)

Ssl连接

engine = sa.create_engine("postgresql+psycopg2://scott:tiger@192.168.0.199:5432/test?sslmode=require"
)
1.2.4 连接MongoDB
engine = create_engine("mongodb:///?Server=MyServer&Port=27017&Database=test&User=test&Password=Password")定义1个mapping类
base = declarative_base()
class restaurants(base):
__tablename__ = "restaurants"
borough = Column(String,primary_key=True)
cuisine = Column(String)

查询:

engine=create_engine("mongodb:///?Server=MyServer&Port=27017&Database=test&User=test&Password=Password")
factory = sessionmaker(bind=engine)
session = factory()
for instance in session.query(restaurants).filter_by(Name="Morris Park Bake Shop"):
print("borough: ", instance.borough)
print("cuisine: ", instance.cuisine)
print("---------")

1.3创建connect 对象

语法:

conn = engine.connect() 

e = create_engine('sqlite:///C:\\myapp\\db\\main.db')
conn = e.connect()

推荐使用context with 语法使用connect对象

from sqlalchemy import create_engine, text
engine = create_engine('sqlite:///C:\\myapp\\db\\main.db')
with engine.connect() as connection:result = connection.execute(text("select username from users"))for row in result:print("username:", row["username"])

如果修改了数据,应调用 conn.commit() 提交transaction

2. SQL Express Language 常用方法

Sqlalchemy 对sql进行了封装,其SQL Express语法比直接使用sql 语句更方便,优势是传参与获取返回值更省事。

2.1 使用 text() 生成SQL Express语句

text()方法是CoreAPI中最基础的方法之一,主要作用,用于封装 sql 语句

from sqlalchemy import textt_sql = text("SELECT * FROM users")
result = connection.execute(t_sql)

传参:

t_sql = text("SELECT * FROM users WHERE id=:user_id")
result = connection.execute(t_sql, { ‘user_id’: 12 } )

如果使用r” “ ,则用 : 来表示:

2.2 bindparams() 方法传参

也可以通过 text(sql_statement).bindparams() 直接构建完整的SQL语句

from sqlalchemy import text, bindparams
stmt = text("SELECT id, name FROM user WHERE name=:name ""AND timestamp=:timestamp")
stmt = stmt.bindparams(name='jack',timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5)
)
result = conn.execute(stmt)
print(result.all())

bindparams()中可添加参数Type检查:

from sqlalchemy import text
stmt = text("SELECT id, name FROM user WHERE name=:name ""AND timestamp=:timestamp")
stmt = stmt.bindparams(bindparam('name', type_=String),bindparam('timestamp', type_=DateTime)
)
stmt = stmt.bindparams(name='jack',timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5))
result = conn.execute(stmt)
print(result.all())

3, 解析查询结果

查询结果类型为 sqlalchemy.engine.Result 类,是1个由 object 组成的列表。可以用多种方法访问:

  • all() , return all rows in a list
  • columns(‘col_1’, ‘col_2’) 指定返回每row 的字段, iterable
  • fetchall(), fetchone(), fetchmany()
  • first() 返回第1行。
  • keys() 返回row的字段名, 是iterable 类型
  • mappings(), 列表元素为dict类型,
  • result.close() 关闭result对象

说明:

  • 遍历查询结果, all()- , fetchall(), fetchmany(), columns(), 结果为: list[tuple,…], 或iterable,
  • 对row 字段, 可以用key, index , row[0], row[‘id’], row[‘name’], 也可以用row.name , 如
result = conn.execute(text("select x, y from some_table"))
for row in result:print(f"Row: {row.x} {row.y}")
  • result.mapping() 返回结果的row 类型为dict,
result = conn.execute(text("select x, y from some_table"))
for dict_row in result.mappings():x = dict_row["x"]y = dict_row["y"]

4. 使用connect 对象执行CRUD操作

SqlAlchemy可以用connect对象与 session 对象来执行SQL express
connect对象是直接调用DBAPI执行SQL语句,这是使用SqlAlchemy 最简单的方式,同时支持部分Sqlalchemy 的SQL Express 封装语法,但执行的SQL语句依然还要符合各数据库的接口库要求。
Session对象则实现了同1套接口适用于所有数据库。但主要用于ORM API方式。

connect对象操作数据库的好处:可使用text()方法生成SQL语句,利用bindparams() 传值,以及做类型检查。同时支持多线程访问数据库。

创建表的方法,前面已讲过。 下面示例为 insert, update, delete 操作

# insert row 
print("-"*50+"Insert operation")
stmt = text("INSERT INTO some_table VALUES(:x, :y)").bindparams(x=6,y=19)
with engine.connect() as conn:conn.execute(stmt)conn.commit()result = conn.execute( text("select * from some_table") )print(result.all())# update row 
print("-"*50+"update operation")
stmt = text("UPDATE some_table SET y=:y WHERE x=:x").bindparams(y=99,x=5)
with engine.connect() as conn:conn.execute(stmt)conn.commit()result = conn.execute( text("select * from some_table") )print(result.all())# delete row 
print("-"*50+"delete operation")
stmt = text("DELETE FROM some_table WHERE x=:x").bindparams(x=4)
with engine.connect() as conn:conn.execute(stmt)conn.commit()result = conn.execute( text("select * from some_table") )print(result.rowcount)print(result.all())

output:

--------------------------------------------------Insert operation
2023-12-03 15:50:36,978 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2023-12-03 15:50:36,978 INFO sqlalchemy.engine.Engine INSERT INTO some_table VALUES(?, ?)
2023-12-03 15:50:36,978 INFO sqlalchemy.engine.Engine [generated in 0.00085s] (6, 19)
2023-12-03 15:50:36,979 INFO sqlalchemy.engine.Engine COMMIT
2023-12-03 15:50:36,980 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2023-12-03 15:50:36,980 INFO sqlalchemy.engine.Engine select * from some_table
2023-12-03 15:50:36,981 INFO sqlalchemy.engine.Engine [generated in 0.00132s] ()
[(1, 1), (2, 4), (3, 10), (4, 11), (5, 25), (6, 19)]
2023-12-03 15:50:36,982 INFO sqlalchemy.engine.Engine ROLLBACK
--------------------------------------------------update operation[(1, 1), (2, 4), (3, 10), (4, 11), (5, 99), (6, 19)]
2023-12-03 15:50:36,985 INFO sqlalchemy.engine.Engine ROLLBACK
--------------------------------------------------delete operation
[(1, 1), (2, 4), (3, 10), (5, 99), (6, 19)]
2023-12-03 15:50:36,989 INFO sqlalchemy.engine.Engine ROLLBACK

5. 表间关系处理

Sqlalchemy 使用DBAPI处理表间关系语法是依据数据库规定, 但基本均支持标准SQL语法

5.1 创建外键字段的语法:

 CREATE TABLE tracks(……trackartist   INTEGER,     -- 外键字段
FOREIGN KEY(trackartist) REFERENCES artist(artistid)
)

辅表artist.id字段须为主键或unique index。

5.2 各种表间关系的实现方式:

  • One to one: 还是用 foreign key来实现。
  • One to many: 就是外键
  • Many to many: 需要中间表, 用2个foreign key 与两张表分别建立 one to many 关系。

示例 :

import sqlalchemyfrom sqlalchemy import create_engine
from sqlalchemy import text
from sqlalchemy.orm import sessionmaker  engine = create_engine("sqlite:///order.db")# create table people 
with engine.connect() as conn:conn.execute(text("drop table if exists people;"))stmt = text("""CREATE TABLE people(id  integer PRIMARY KEY,name TEXT, age  INTEGER)""" )conn.execute(stmt)conn.execute(text("INSERT INTO people (id,name, age) VALUES (:id,:name, :age)"),[ {'id': 1, "name": 'Jack','age':30 }, {'id': 2, "name": 'Smith','age':28 }, {'id': 3, "name": 'Wang','age':35 }, ])conn.commit()result = conn.execute( text("select * from people") )print(result.rowcount)print(result.all())# create table order
# 创建会话(Session)  
with engine.connect() as conn: conn.execute(text("drop table if exists teams"))stmt_1 = text("""create table teams(id  integer PRIMARY KEY,team_name  TEXT, pid  integer,foreign key (pid) REFERENCES people(id))""")conn.execute(stmt_1)conn.commit()conn.execute(text("INSERT INTO teams (id, team_name, pid) VALUES (:id, :team_name, :pid)"),[ {'id': 101, "team_name": 'TV product','pid':1 }, {'id': 102, "team_name": 'Software development','pid':2 }, {'id': 103, "team_name": 'Electric development','pid':2 }, ])
conn.commit()# 跨表查询result = conn.execute( text("select a.id, a.team_name, b.name from teams as a left join people as b on a.pid=b.id") )print(result.rowcount)for row in result.mappings():print(row['id'], row['team_name'], row['name'])

6. 通过多线程访问Database

sqlalchemy的engine可做为全局变量, 将connect对象,或 session对象传入线程,实现多线程访问:

示例:

def thread_db(conn,name):try:  result = conn.execute( text("select * from people") )print(result.rowcount)print(f"thread {{ name }} result: ")print(result.all())except Exception as e:print("can't open connection object")finally: conn.close()from threading import Threadt1 = Thread(target=thread_db, args=(engine.connect(),"thread_a"))
t2 = Thread(target=thread_db, args=(engine.connect(),"thread_b"))
t1.start()
t2.start()
t1.join()
t2.join()
print("main thread is ended")
output: 
thread { name } result:
thread { name } result:
[(1, 'Jack', 30), (2, 'Smith', 28), (3, 'Wang', 35)]
[(1, 'Jack', 30), (2, 'Smith', 28), (3, 'Wang', 35)]
main thread is ended

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/620998.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TS2307: Cannot find module ‘./App.vue‘ or its corresponding type declarations.

目录 1. 问题描述2. 解决方案一:VSCode Volar(官方推荐)3. 解决方案二:WebStorm 2023.2 (官方推荐)4. 解决方案三:禁用严格类型检查选项(不推荐)5. 解决方案四&#xff…

大模型实战营Day5 LMDeploy大模型量化部署实践

模型部署 定义 产品形态 计算设备 大模型特点 内存开销大 动态shape 结构简单 部署挑战 设备存储 推理速度 服务质量 部署方案:技术点 (模型并行 transformer计算和访存优化 低比特量化 Continuous Batch Page Attention)方案(…

rpc的正确打开方式|读懂Go原生net/rpc包

前言 大家好,这里是白泽,之前最近在阅读字节跳动开源RPC框架Kitex的源码,分析了如何借助命令行,由一个IDL文件,生成client和server的脚手架代码,也分析了Kitex的日志组件klog。当然Kitex还有许多其他组件&…

RXJS中Subject, BehaviorSubject, ReplaySubject, AsyncSubject的区别?

在RxJS(Reactive Extensions for JavaScript)中,Subject、BehaviorSubject、ReplaySubject和AsyncSubject都是Observable的变体,它们用于处理观察者模式中的不同场景。以下是它们之间的主要区别: 1、Subject: 是一种特…

在ubuntu平台上安装minecraft

一、获取minecraft启动器安装包 登陆minecraft官网Welcome to the Minecraft Official Site | Minecraft,使用已经购买minecraft的microsoft或者mojang账号登陆。 点击Download Launcher 对于ubuntu系统,使用点击debian版本 此后便会自动下载Minecraft.…

【STM32】FLASH闪存

1 FLASH闪存简介 本节所指STM32内部闪存,即下载程序的时候,程序存储的地方。(非易失性) STM32F1系列的FLASH包含程序存储器、系统存储器(bootloader,不允许修改)和选项字节三个部分&#xff0…

Spring Cloud整体架构解析

Spring Cloud整体架构 本文已收录至我的个人网站:程序员波特,主要记录Java相关技术系列教程,共享电子书、Java学习路线、视频教程、简历模板和面试题等学习资源,让想要学习的你,不再迷茫。 Spring Cloud的中文名我们就…

pytorch学习笔记(八)

Sequential 看看搭建了这个能不能更容易管理,CIFAR-10数据集进行 看一下网络模型CIFAR-10模型 1 2 3 4 5 6 7 8 9 输入进过一次卷积,然后经过一次最大池化&#…

YOLOv7基础 | 手把手教你简化网络结构之yolov7.yaml(包括源码+封装步骤+网络结构图)

前言:Hello大家好,我是小哥谈。通过下载YOLOv7源码可知,原始的yolov7.yaml文件是拆开写的,比较混乱,也不好理解,并且为后续改进增添了很多困难。基于此种情况,笔者就给大家介绍一种将yolov7.yam…

深入理解 Spark(三)SparkTask 执行与 shuffle 详解

SparkTask 的分发部署与启动流程分析 Spark Action 算子触发 job 提交 Spark 当中 Stage 切分源码详解 Task 的提交与执行 SparkShuffle 机制详解 MapReduceShuffle 全流程深度剖析 MapReduce 全流程执行过程中参与工作的组件以及他们的执行先后顺序:InputFormat …

【AIGC】电影风格的一组绝美高清图提示词解析

实际示例 女人主角,以时尚电影风格为灵感,追求照片般的逼真度,运用伦勃朗式光线,创造奇幻且细节丰富的场景,充满象征意义,使用3D渲染技术达到8K超高清晰度。 分类相关信息主角女人风格时尚电影风格逼真度…

LLM漫谈(三)| 使用Chainlit和LangChain构建文档问答的LLM应用程序

一、Chainlit介绍 Chainlit是一个开源Python包,旨在彻底改变构建和共享语言模型(LM)应用程序的方式。Chainlit可以创建用户界面(UI),类似于由OpenAI开发的ChatGPT用户界面,Chainlit可以开发类似…

5 个适用的免费数据恢复软件【2024 年 版本】

互联网上有许多免费的数据恢复软件产品。有些产品是免费软件,而其他产品则提供该工具的免费试用下载以进行评估。我们列出了2024 年 5 款最佳数据恢复工具 ,可以免费下载和试用。 5 个适用的免费数据恢复软件 1.奇客数据恢复(Windows和Mac&am…

Apache-Common-Pool2中对象池的使用方式

最近在工作中,对几个产品的技术落地进行梳理。这个过程中发现一些朋友对如何使用Apache的对象池存在一些误解。所以在写作“业务抽象”专题的空闲时间里,本人觉得有必要做一个关于对象池的知识点和坑点讲解。Apache Common-Pool2 组件最重要的功能&#…

中仕公考:2024年上半年中小学教师资格考试(笔试)报名已开始

2024年上半年中小学教师资格考试(笔试)报名工作于1月12日开始,此次笔试在31个省(自治区、直辖市)举办,各省(自治区、直辖市)的报名公告将陆续上网。 个别地区报名截止时间有所差异,上海1月13日报名截止,浙江、天津、河南1月14日截…

负荷预测 | Python基于CEEMDAN-VMD-BiGRU的短期电力负荷时间序列预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 提出一种分解去噪、重构分解的 CEEMDAN-VMD-BiGRU组合预测方法: 1 采用CEEMDAN将原始电力负荷数据分解成一组比较稳定的子序列,联合 小波阈值法将含有噪声的高频分量去噪,保留含有信…

微服务技术要点

一、服务注册到nacos 1.下载nacos,修改nacos启动模式为单机模式,另外需要在环境变量配置JAVA_HOME,否则启动不起来。 2.启动类加注解EnableDiscoveryClient 3.application.yml配置nacos地址 spring:cloud:nacos:discovery:server-addr: 127.0.0.1:884…

springboot怎样设置全局的traceId(包括MQ)

一、Controller打印TraceId 1、拦截所有的controller,输入输出将traceId放入MDC中: package com.perkins.ebicycle.mobile.trace;import java.util.Arrays; import java.util.List; import java.util.UUID; import java.util.stream.Collectors;import…

华为设备登录安全配置案例

知识改变命运,技术就是要分享,有问题随时联系,免费答疑,欢迎联系! 厦门微思网络​​​​​​ https://www.xmws.cn 华为认证\华为HCIA-Datacom\华为HCIP-Datacom\华为HCIE-Datacom Linux\RHCE\RHCE 9.0\RHCA\ Oracle O…

Python+甘特图及标签设置

图示 甘特图代码 import matplotlib.pyplot as plt import numpy as npclass ProjectEmement:def __init__(self, name_, starttime_: float, endtime_: float, fact_endtime_: float, grade_, rootlist_: list, keylist_: list, isover_=-1):self.name = name_self.starttime…