sqlalchemy is important(2)

来源:互联网 发布:电视机顶盒网络设置 编辑:程序博客网 时间:2024/05/23 14:16

有必要了解一下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.csdn.net/dupei/article/details/6014488

0 0
原创粉丝点击