sqlalchemy2.0使用记录

简介

SQLAlchemy 实际上它分为两部分——底层的 Core 和上层的传统 ORM。

  • Core 是SQLAlchemy作为“数据库工具包”的基础架构。该库提供了用于管理与数据库的连接、与数据库查询和结果交互以及SQL语句的编程构造的工具。 ORM 以核心为基础提供可选 对象关系映射 能力。
  • ORM提供了一个附加的配置层,允许用户定义的Python类 映射 以及一种称为 会话 . 然后,它扩展了核心级别的SQL表达式语言,允许按照用户定义的对象组合和调用SQL查询。

如何选择?

  • 虽然你使用的框架中已经内置了ORM,但是希望添加更强大的报表功能,请选用Core。
  • 如果你想在一个一模式为中心的视图中查看数据(用户类似于SQL),请使用Core。
  • 如果你的数据不需要业务对象,请使用Core。
  • 如果你要把数据看作业务对象,请使用ORM。
  • 如果你想快速创建原型,请使用ORM。
  • 如果你需要同事使用业务对象和其他与问题域无关的数据,请组合使用Core和ORM。

创建链接

from sqlalchemy import create_engine

engine = create_engine(
    "mysql://user:password@localhost:3306/dbname",
    echo=True,  # echo 设为 true 会打印出实际执行的 sql,调试的时候更方便
    future=True,  # 使用 2.0API,向后兼容
    pool_size=5, # 连接池的大小默认为 5 个,设置为 0 时表示连接无限制
    pool_recycle: 3600, # 设置时间以限制数据库多久没连接自动断开。
)

Core的使用方式

使用text、select、insert、update和delete等构造SQL,再由execute执行。实践中推荐SQL与SQL执行分开,尤其是较为复杂的SQL。

使用纯SQL

  • 无参数
stmt=text("select * from db_name")
with engine.connect() as conn:
     result = conn.execute(stmt)
     print(result.all())
  • 有参数
  1. 方式一,多参数
with engine.connect() as conn:
    stmt=text("INSERT INTO some_table (x, y) VALUES (:x, :y)")
    params=[{"x": 1, "y": 1}, {"x": 2, "y": 4}]
    conn.execute(stmt,params)
    conn.commit()
  1. 方式二,与语句绑定
with engine.connect() as conn:
    stmt=text("INSERT INTO some_table (x, y) VALUES (:x, :y)").bindparams([{"x": 1, "y": 1}, {"x": 2, "y": 4}])
    conn.execute(stmt)
    conn.commit()

方式风格

  • 边做边做
with engine.connect() as conn:
    stmt=...
    conn.execute(stmt)
  • 开始一次(推荐)

此方法将同时管理 Connection并在事务结束时使用COMMIT将事务内部的所有内容括起来,假设块成功,或者在异常引发时回滚

with engine.begin() as conn:
    stmt=text("INSERT INTO some_table (x, y) VALUES (:x, :y)").bindparams([{"x": 1, "y": 1}, {"x": 2, "y": 4}])
    conn.execute(stmt)

获取与使用查询结果

execute()函数的返回值是一热ResultProxy对象,它允许使用索引、名称或Column对象进行访问。

  • 元组赋值,即解包,在接收到变量时将变量按位置分配给每一行
result = conn.execute(text("select x, y from some_table"))
for x, y in result:
    .....
  • 属性名称,元组具有与每个列的名称相匹配的动态属性名。这些名称通常是SQL语句为每行中的列指定的名称
result = conn.execute(text("select x, y from some_table"))

for row in result:
    y = row.y

    # illustrate use with Python f-strings
    print(f"Row: {row.x} {row.y}")
  • 属性名称与模型结合,即结果类型映射,个人更喜欢这种方式,编程效率会更高
result = conn.execute(text("select x, y from some_table"))
result:[TableModel]=result.fetchall()
for row in result:
    y = row.y

    # illustrate use with Python f-strings
    print(f"Row: {row.x} {row.y}")
  • 整数索引,不推荐

使用ORM会话执行Session

使用ORM时,基本的事务/数据库交互对象称为 Session

>>> from sqlalchemy.orm import Session

>>> stmt = text("SELECT x, y FROM some_table WHERE y > :y ORDER BY x, y").bindparams(y=6)
>>> with Session(engine) as session:
...     result = session.execute(stmt)
...     for row in result:
...        print(f"x: {row.x}  y: {row.y}")

映射Python类

在 1.4 版更改: 声明性映射和经典映射现在被称为“声明性”和“命令式”映射,并且在内部是统一的

  • 命令式(Table类)
student = Table('student', metadata,
            Column('id', Integer, primary_key=True),
            Column('name', String(50), ),
            Column('age', Integer),
            Column('address', String(10)),
)
  • 声明式(模型类)
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()   # 生成模型类的基类

class User(Base):   # 模型类必须通过继承基类来获得metadata
    __tablename__ = 'users'   # 声明需要映射的表名
    id = Column(Integer,primary_key=True)
    name = Column(String(20),nullable=False)

使用类模型

实践中使声明式会更方便些

select_stmt = select(User.id, User.name).where(User.id == 41865)
insert_stmt = insert(User).values(name='name1')
with engine.begin() as beg:
    beg.execute(select_stmt)
    beg.execute(insert_stmt)

ORM 使用方式

Session是对transcation的封装,最重要的功能是实现原子操作。要完成数据库查询,就需要建立与数据库的连接。这就需要用到Engine对象。一个Engine可能是关联一个Session对象,也可能关联一个数据库表。一旦任务完成 session 会将数据库 connection 交还给 pool。

建立session链接

future=True 使用2.0API

from sqlalchemy.orm import sessionmaker

DBSession = sessionmaker(bind=engine,autocommit=False, autoflush=False,
                                                  future=True)

with DBSession() as sess:
    sess.execute()

with DBSession.begin() as sess:
    sess.execute()

session的四种状态

ORM模型很方便地将数据库中的一条条记录转变成了python中的一个个对象,有时候我们会想当然地把两者完全等同起来,但是不要忘了,两者之间还必须有session这个中间的桥梁。因为有session在中间做控制,所以必须注目对象和记录之间一个状态上的差别。一般而言,一个数据的对象可以有四种不同的和session关联的状态。

from sqlalchemy.orm import sessionmaker

DBSession = sessionmaker(bind=engine)
session = DBSession()                   #创建session对象
frank = Person(name='Frank')    #数据对象得到创建,此时为Transient状态
session.add(frank)                      #数据对象被关联到session上,此时为Pending状态
session.commit()                            #数据对象被推到数据库中,此时为Persistent状态
session.close()                             #关闭session对象
print (frank.name)                      #此时会报错DetachedInstanceError,因为此时是Detached状态。

new_session = DBSession()
print (new_session.query(Person).get(1).name)    #可以查询到数据
new_session.close()

增删改查


insert_stmt = insert(User).values(name='name1')
with DBSession() as sess:
    sess.execute(insert_stmt)
    sess.commit()
    

insert_stmt2 = insert(User)
with DBSession() as sess:
    sess.execute(insert_stmt2,{'name':'name1'})
    sess.commit()
    

with DBSession() as sess:
    sess.execute(insert_stmt2,[{'name':'name1'},{'name':'name2'}])
    sess.commit()
    

with DBSession.begin() as sess:
    sess.execute(insert_stmt2,[{'name':'name1'},{'name':'name2'}])


obj=User(name='name2')
with DBSession() as sess:
    sess.add(obj)
    sess.commit()


obj=User(name='name2')
obj2=User(name='name2')
with DBSession() as sess:
    sess.add(obj)
    sess.add(obj2)
    # 或者 s.bulk_save_objects([obj,obj2])
    sess.commit()
  • 查、改和删

2.0 API 中不再使用 query,而是使用 select,update,delete 来操作数据。但query仍可使用

# session.query(User).get(42)
session.get(User, 42)

# session.query(User).all()
session.execute(select(User)).scalars().fetchall()

# session.query(User).filter_by(name="some_user").first()
session.execute(select(User).filter_by(name="some_user")).fetchone()

# session.query(User).from_statememt(text("select * from users")).a..()
session.execute(select(User).from_statement(text("selct * from users"))).scalars().all()

# session.query(User).filter(User.name == "foo").update({"fullname": "FooBar"}, synchronize_session="evaluate")
session.execute(update(User).where(User.name == "foo").values(fullname="FooBar").execute_options(synchronize_session="evaluate"))
# synchronize_session 有三种选项: false, "fetch", "evaluate",默认是 evaluate
# false 表示完全不更新 Python 中的对象
# fetch 表示重新从数据库中加载一份对象
# evaluate 表示在更新数据库的同时,也尽量在 Python 中的对象上使用同样的操作

自动生成模型


sqlacodegen --outfile=models.py mysql://root:[email protected]:3306/test --tables teacher,student

sqlacodegen --outfile=models.py mysql://root:[email protected]:3306/test --tables teacher,student ----noclasses

你可能感兴趣的:(sqlalchemy2.0使用记录)