sqlalchemy is important(2)

本文深入探讨SQLAlchemy的核心概念,包括SQLAlchemyCore与ORM功能,以及如何在openstack环境中优化数据库。通过实例展示了如何使用SQLAlchemy创建数据库表,以及在openstack中常见Model的定义与操作。此外,详细解释了Session的作用及其事务性保证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有必要了解一下sqlalchemy的一些基本概念,当然了没有比官方文档更好的地方,官网的文档写的也算是简介明了,以其为主:

http://docs.sqlalchemy.org/en/rel_1_0/

如果你不是关注与openstack的数据库方面,比如百度的人搞openstack貌似想做这方面的东西,他们想优化openstack的数据库。

从网络上或者官网上可以看到sqlalchemy分为两部分:

SQLAlchemy Core  #sql语言构造器,写起来和直接call sql语句很像

SQLAlchemy ORM  #ORM功能,对象关系映射,这个是一个专门的方向,东西很多

当我们使用SQLAlchemy core时候,数据库作为一个一个的表而存在,每一条数据是一行,而在ORM中,数据成为类,而每一条数据是类的一个实例,

我们可以认为先有的core,而后在core的基础上实现的ORM。


上一篇说sqlalchemy封装了不同数据库的操作,在core中创建表(216_havana.py中取了一个例子):

    meta = MetaData()
    meta.bind = migrate_engine


    agent_builds = Table('agent_builds', meta,
        Column('created_at', DateTime),
        Column('updated_at', DateTime),
        Column('deleted_at', DateTime),
        Column('id', Integer, primary_key=True, nullable=False),
        Column('hypervisor', String(length=255)),
        Column('os', String(length=255)),
        Column('architecture', String(length=255)),
        Column('version', String(length=255)),
        Column('url', String(length=255)),
        Column('md5hash', String(length=255)),
        Column('deleted', Integer),
        mysql_engine='InnoDB',
        mysql_charset='utf8'
    )

数据库中Table定义时,最终用的是metadata,你可以认为在metadata中指明了创建(操作)数据库表时使用的engine是什么。

使用agent_builds.create()即可创建database中的表,一旦表被创建,则可以如下使用Table:

table = Table('project_user_quotas', meta, autoload=True)

i=table.insert()

i.execute(xxxxxx) #执行插入动作

在nova/test/db的case中我们可以看到:

table.insert().execute(fake_quotas)
# Check we can get the longest resource name.
quota = table.select(table.c.id == 5).execute().first()

其中table.c访问table中的colums


在mark的link中有一段话对sqlalchemy的ORM作用说的比较明白:

”使用ORM,你可以将表格(和其他可以查询的对象)同Python联系起来,放入映射集(Mappers)当中。

然后你可以执行查询并返回 对象实例 列表,而不是结果集。 对象实例 也被联系到一个叫做 Session 的对象,

确保自动跟踪对象的改变,并可以使用 flush 立即保存结果。“

类将会和数据库中的Table关联起来,这时怎么做到的呢,如果自己实现,很容易想到这就是天然的“map”,将table和

class 做个mapping就可以了(可能需要双向的map存在),事实上,sqlalchemy中也是类似的,称之为mapper,官网的

教程有一篇叫“Declare a Mapping”说的就是这个。

>>> from sqlalchemy.ext.declarative import declarative_base
>>> Base = declarative_base()

>>> from sqlalchemy import Column, Integer, String
>>> class User(Base):
...     __tablename__ = 'users'
...
...     id = Column(Integer, primary_key=True)
...     name = Column(String)
...     fullname = Column(String)
...     password = Column(String)
...
...     def __repr__(self):
...        return "<User(name='%s', fullname='%s', password='%s')>" % (
...                             self.name, self.fullname, self.password)


这已经和openstack中的非常相似了,我们在nova/db/models.py中随便看一个定义的Model:

class Service(BASE, NovaBase):#此处Base便是declarative_base()
    """Represents a running service on a host."""

    __tablename__ = 'services' #指明table名
    __table_args__ = (
        schema.UniqueConstraint("host", "topic", "deleted",
                                name="uniq_services0host0topic0deleted"),
        schema.UniqueConstraint("host", "binary", "deleted",
                                name="uniq_services0host0binary0deleted")
#唯一性限制,很容易理解,host,binary和deleted三个属性组成的字段具有唯一性
        )

    id = Column(Integer, primary_key=True)
    host = Column(String(255))  # , ForeignKey('hosts.id'))
    binary = Column(String(255))
    topic = Column(String(255))
    report_count = Column(Integer, nullable=False, default=0)
    disabled = Column(Boolean, default=False)
    disabled_reason = Column(String(255))

#至于Index之类的都很好理解,不再赘述,有一些数据库基础的理解起来都不难

另一个父类NovaBase,其中主要实现了save方法,

def save(self, session=None):
        from nova.db.sqlalchemy import api
        if session is None:
            session = api.get_session()
        super(NovaBase, self).save(session=session)

这也就是我们在nova/db/api.py中看到有些操作中:

service_ref = models.Service()
service_ref.update(values)

service_ref.save()

类似的操作save是如何工作的,就是因为NovaBase的原因。


在数据库操作的部分,我们常能看到“session”,session是什么呢?

所有对映射的操作都需要一个重要的对象叫做 Session 。所有对象通过映射的载入和保存都 必须 通过 Session 对象,有如对象的工作空间一样被加载到内存。

特定对象在特定时间只能关联到一个 Session 。


我理解成为,要想通过类操作变成为数据库操作,需要通过映射,同时需要通过session,像是真正操作数据库的连接。

session的另一个重要特性是其事务性的保证,

 transaction=session.create_transaction()

transaction.commit()

transaction.rollback()

可以用于事务性的控制,在neutron中,只有网络命名执行成功,数据库的变化才会commit,就是这个用法。


sqlalchemy的东西本身是比较深比较多的,话说回来,数据库就不简单,对于sqlalchemy core在migrate_repo中使用较多,由于涉及到对表的创建,

更改等,sqlalchemy orm的使用,nova/db/api.py中使用较多,实际的openstack大部分操作最终都会到db中定义的操作来,而这时基本是ORM的使用

场景。


mark link这一篇讲的不错

http://blog.youkuaiyun.com/dupei/article/details/6014488

### SQLAlchemy 2 版本常用查询方法 在SQLAlchemy 2版本中,常用的查询方式主要通过`Session`对象来执行。对于定义好的模型类如`User`,可以利用会话(session)来进行各种类型的查询。 #### 使用 Session 进行简单查询 为了创建一个用于查询的session,通常需要先建立引擎(engine),并配置好相应的数据库连接字符串。之后使用`sessionmaker`绑定engine得到一个新的session实例[^1]。 ```python from sqlalchemy.orm import sessionmaker from Models import User, engine # 创建DBSession类型: DBSession = sessionmaker(bind=engine) # 创建session对象: session = DBSession() ``` 有了session后,可以通过它对特定表的数据进行增删改查操作。下面是一些基本的例子: - **获取所有记录** 当想要检索某张表中的全部数据时,可以直接调用all()函数: ```python users = session.query(User).all() for user in users: print(f'{user.id}, {user.name}') ``` - **基于条件筛选** 如果只关心满足某些条件的结果,则可以在query后面加上filter或者filter_by方法指定过滤规则: ```python young_users = session.query(User).filter(User.age < 30).all() specific_user = session.query(User).filter_by(name='Alice').first() if specific_user is not None: print(specific_user.age) ``` - **分页显示** 有时候返回太多条目可能不合适,在这种情况下可以用limit和offset实现简单的分页功能: ```python page_size = 10 start_from = (current_page - 1) * page_size paged_users = session.query(User).order_by(User.id.desc()).limit(page_size).offset(start_from).all() ``` - **统计数量** 要计算符合条件的对象数目,count是一个非常方便的方法: ```python total_count = session.query(User).count() filtered_count = session.query(User).filter(User.age >= 18).count() print(total_count, filtered_count) ``` - **exists子查询** 存在性判断也是常见的需求之一,这可通过exists表达式完成。比如检查是否存在某个用户名字叫Bob的人: ```python has_bob = session.query(exists().where(User.name == 'Bob')).scalar() print(has_bob) # 输出True或False ``` 以上就是一些基础却实用的SQLAlchemy查询技巧,适用于大多数场景下的CRUD操作[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值