sqlalchemy2.0使用记录

2021-09-01  本文已影响0人  大豆田

简介

SQLAlchemy 实际上它分为两部分——底层的 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:
    .....
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 版更改: 声明性映射和经典映射现在被称为“声明性”和“命令式”映射,并且在内部是统一的

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()

增删改查

<!--方式一SQL-->
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()
    
<!--另一种方式begin-->
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 中的对象上使用同样的操作

自动生成模型

<!--生成映射模型,即Class模型-->
sqlacodegen --outfile=models.py mysql://root:guess@192.168.1.250:3306/test --tables teacher,student
<!--生成命令模型,即Table模型-->
sqlacodegen --outfile=models.py mysql://root:guess@192.168.1.250:3306/test --tables teacher,student ----noclasses
上一篇 下一篇

猜你喜欢

热点阅读