添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
文雅的小蝌蚪  ·  XWPF2XHTMLConverter ...·  5 月前    · 
独立的拐杖  ·  dlmopen ...·  6 月前    · 
含蓄的火锅  ·  Coins – Taste of ...·  11 月前    · 

SQLAlchemy 是Python最广泛使用的一个ORM(对象关系映射,简单地说就是把数据库的表即各种操作映射到Python对象上面来)工具。它支持操作 PostgreSQL MySQL Oracle Microsoft SQL Server SQLite 等支持SQL的数据库。 文档地址

  • 需要特别注意的是, SQLAlchemy 只是适用于一些通用的微型框架,而全栈框架 Django 的orm在结合特定框架用起来可能更加便利,所以在使用 SQLAlchemy 的时候,如果不知道怎么完成复杂的定义,那就干脆自己写sql吧,自己去join什么的
  • 有另外一个选择 peewee ,提供类似Django那样又好的查询API,比 SQLAlchemy 易用,虽然可能没那么强大,性能可能也没那么好(并没有人去对比过性能),但是 peewee 还不支持 Oracle 等数据库,虽然我不用,但是为了防止以后多学习一门,就决定是 SQLAlchemy
  • SQLAlchemy 本身并不支持异步,在 tornado/sanic 中只有手动去执行异步
  • SQLAlchemy安装

    1
    pip install sqlalchemy

    SQLAlchemy连接数据库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 初始化数据库连接
    ## echo默认为False,当为True的时候,会把sqlalchemy的所有日志包括连接数据库后做的所有操作都会打印出来,对于调试来说是非常方便的
    ## pool_size是连接池中连接的数量
    ## max_overflow指允许的最大连接池大小,当超过pool_size后如果仍需要连接仍然可以创建新的连接,而当超过max_overflow后则不会创建新的连接,必须等到之前的连接完成以后,默认为10,为0表示不限制
    ## pool_recycle表示连接在给定时间之后会被回收,不能超过8小时
    ## pool_timeout表示等待多少秒后,如果仍然没有获取到连接则放弃获取
    ## pool_pre_ping表示每次取出一个连接时,会发送一个select 1来检查连接是否有效
    engine = create_engine('postgresql://scott:tiger@localhost/mydatabase')
    engine = create_engine('mysql://scott:tiger@localhost/foo?charset=utf8', echo=True, pool_size=5, max_overflow=10, pool_recycle=-1, pool_timeout=30, pool_pre_ping=True)
    engine = create_engine('oracle://scott:[email protected]:1521/sidname')
    engine = create_engine('sqlite:///foo.db')

    DBSession = sessionmaker(bind=engine, autocommit=True) # 创建DBSession类型,可视为当前数据库的连接
    session = DBSession() # 创建一个session对象

    # session基本操作
    new_user = User(id='1', name='haofly') # 新建一个User对象
    session.add(new_user)
    session.commit() # 提交
    session.close() # 关闭session

    需要注意的是,如果没有修改autocommit的默认值(False),那么一个session会一直保持,直到该session被回滚、关闭、提交才结束。每次发起请求,都创建一个新的session(注意不是创建新的连接,创建session并不会有多大的开销),一个session就是一个transaction的支持。我们可以让session是一个全局的对象,这样和数据库通信的session在任何时候只有一个,但是全局的session不是线程安全的,如果多线程的情况下,可能会造成commit错乱, tornado 这种单线程程序由于其异步的特性也不可以那样做(Tornado可以在每个 Handler 的初始化进行session的创建与提交销毁)。当然,如果是在单线程的情况下,我们完全可以保持session的单例,减少一丢丢的开销。下面这种方式对于多线程还是单现成都是非常推荐的做法:

    1
    2
    3
    4
    5
    6
    7
    8
    from sqlalchemy.orm import scoped_session
    from sqlalchemy.orm import sessionmaker

    session_factory = sessionmaker(bind=some_engine)
    Session = scoped_session(session_factory) # 为了保证线程获得的session对象是唯一的
    some_session = Session()
    some_other_session = Session()
    some_session is some_other_session # True,在一个线程里面创建的session对象都是一样的了。

    Model/数据表定义

    表定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from sqlalchemy.ext.declarative import declarative_base

    Base = declarative_base()
    class User(Base):
    __tablename__ = 'users' # 定义列名
    __mapper_args__ = {'column_prerfix': '_'} # 自动给所有的列添加一个前缀
    id = Column('user_id', Integer, primary_key=True)

    class __str__(self): # print(object)的时候输出的,默认仅输出类名
    return f'<{self.__class__.__module__}.{self.__class__.__name__}(id={self.id})>'

    User.__table__.columns # 获取table中定义的字段(这种方式获取到的字段不会包括关系那些字段)

    列定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    # 列类型
    ## 数字
    BigInteger # 长整型
    Boolean # 布尔值
    Enum # 枚举值,例如Column(Enum('A', 'B")),对象取值的时候,取出来的字段是Enum对象,需要.value才能得到真正的值
    Float
    SmallInteger
    Integer(unsigned=False) # 整型
    Interval
    Numeric
    ## 字符
    JSON
    LargeBinary(length=None) # 二进制
    PickleType # pickle类型
    SchemaType
    String(50) # 字符串varchar类型,括号里表示长度
    Text(length=None)
    Unicode
    UnicodeText
    ## 时间
    Date
    DateTime # daatetime.datetime()对象
    Time # datetime.time()对象
    TIMESTAMP # 时间戳,赋值时需要用datetime.datetime.utcnow()

    # 关联列属性
    fullname = column_property(firstname + ' ' + lastname) # 表示这一列的值由指定的列值确定

    # 列属性
    primary_key=True # 是否是主键
    comment='' # 注释,1.2版本才有的新特性
    table_name.column_name.name # .name获取真实的列名
    nullable=False # 是否可为空,默认为True

    关联关系定义