Cockroach数据库

CockroachDB (CRDB)得到了peewee的大力支持。

from playhouse.cockroachdb import CockroachDatabase

db = CockroachDatabase('my_app', user='root', host='10.1.0.8')

如果您正在使用 Cockroach Cloud ,您可能会发现使用连接字符串指定连接参数更容易:

db = CockroachDatabase('postgresql://root:secret@host:26257/defaultdb...')

备注

CockroachDB需要 psycopg2 (Postgres)Python驱动程序。

备注

CockroachDB安装和入门指南可在此处找到:https://www.cockroachlabs.com/docs/stable/install-cockroachdb.html

安全套接字层配置

在运行Cockroach群集时,强烈建议使用SSL证书。但是,您可能需要在初始化数据库时指定一些额外的选项:

db = CockroachDatabase(
    'my_app',
    user='root',
    host='10.1.0.8',
    sslmode='verify-full',  # Verify the cert common-name.
    sslrootcert='/path/to/root.crt')


# Or, alternatively, specified as part of a connection-string:
db = CockroachDatabase('postgresql://root:secret@host:26257/dbname'
                       '?sslmode=verify-full&sslrootcert=/path/to/root.crt'
                       '&options=--cluster=my-cluster-xyz')

有关客户端验证的更多详细信息,请访问 libpq docs

蟑螂扩展接口

这个 playhouse.cockroachdb 扩展模块提供以下类和助手:

使用CRDB时可能有用的特殊字段类型:

  • UUIDKeyField -使用CRDB的主键字段实现 UUID 使用默认随机生成的UUID键入。

  • RowIDField -使用CRDB的主键字段实现 INT 使用默认值键入 unique_rowid() .

  • JSONField -和博士后一样 BinaryJSONField ,因为CRDB将JSON视为JSONB。

  • ArrayField -与Postgres扩展相同(但不支持多维数组)。

CRDB与Postgres的wire协议兼容,并且公开了一个非常相似的SQL接口,因此它是可能的(尽管 未推荐的 )使用 PostgresqlDatabase 使用CRDB:

  1. CRDB不支持嵌套事务(保存点),因此 atomic() 方法已实现,以便在使用 CockroachDatabase . 了解更多信息 CRDB事务 .

  2. CRDB可能在字段类型、日期函数和Postgres的自省方面有细微差别。

  3. CRDB的特定功能由 CockroachDatabase ,例如指定事务优先级或 AS OF SYSTEM TIME 条款。

CRDB事务

CRDB不支持嵌套事务(保存点),因此 atomic() 方法在 CockroachDatabase 已修改为在遇到无效嵌套时引发异常。如果希望能够嵌套事务性代码,可以使用 transaction() 方法,该方法将确保最外层的块将管理事务(例如,退出嵌套块不会导致提前提交)。

例子:

@db.transaction()
def create_user(username):
    return User.create(username=username)

def some_other_function():
    with db.transaction() as txn:
        # do some stuff...

        # This function is wrapped in a transaction, but the nested
        # transaction will be ignored and folded into the outer
        # transaction, as we are already in a wrapped-block (via the
        # context manager).
        create_user('some_user@example.com')

        # do other stuff.

    # At this point we have exited the outer-most block and the transaction
    # will be committed.
    return

CRDB提供客户端事务重试,使用特殊的 run_transaction() 帮手。这个helper方法接受callable,它负责执行任何可能需要重试的事务语句。

最简单的例子 run_transaction()

def create_user(email):
    # Callable that accepts a single argument (the database instance) and
    # which is responsible for executing the transactional SQL.
    def callback(db_ref):
        return User.create(email=email)

    return db.run_transaction(callback, max_attempts=10)

huey = create_user('huey@example.com')

备注

这个 cockroachdb.ExceededMaxAttempts 如果在给定的尝试次数后无法提交事务,将引发异常。如果SQL格式错误、违反约束等,则函数将向调用方引发异常。

使用示例 run_transaction() 要对将金额从一个帐户转移到另一个帐户的事务执行客户端重试:

from playhouse.cockroachdb import CockroachDatabase

db = CockroachDatabase('my_app')


def transfer_funds(from_id, to_id, amt):
    """
    Returns a 3-tuple of (success?, from balance, to balance). If there are
    not sufficient funds, then the original balances are returned.
    """
    def thunk(db_ref):
        src, dest = (Account
                     .select()
                     .where(Account.id.in_([from_id, to_id])))
        if src.id != from_id:
            src, dest = dest, src  # Swap order.

        # Cannot perform transfer, insufficient funds!
        if src.balance < amt:
            return False, src.balance, dest.balance

        # Update each account, returning the new balance.
        src, = (Account
                .update(balance=Account.balance - amt)
                .where(Account.id == from_id)
                .returning(Account.balance)
                .execute())
        dest, = (Account
                 .update(balance=Account.balance + amt)
                 .where(Account.id == to_id)
                 .returning(Account.balance)
                 .execute())
        return True, src.balance, dest.balance

    # Perform the queries that comprise a logical transaction. In the
    # event the transaction fails due to contention, it will be auto-
    # matically retried (up to 10 times).
    return db.run_transaction(thunk, max_attempts=10)

CRDB应用程序接口

class CockroachDatabase(database[, **kwargs])

CockroachDB数据库实现,基于 PostgresqlDatabase 并使用 psycopg2 驱动程序。

其他关键字参数被传递给psycopg2连接构造函数,并可用于指定数据库 userport 等。

或者,可以以URL形式指定连接详细信息。

run_transaction(callback[, max_attempts=None[, system_time=None[, priority=None]]])
参数:
  • callback -- 可赎回的,接受单一 db 参数(将是此方法从中调用的数据库实例)。

  • max_attempts (int) -- 放弃前尝试的最大次数。

  • system_time (datetime) -- 执行交易 AS OF SYSTEM TIME 相对于给定值。

  • priority (str) -- “低”、“正常”或“高”。

返回:

返回回调返回的值。

加薪:

ExceededMaxAttempts 如果 max_attempts 超过了。

在事务中运行SQL,并在客户端自动重试。

用户提供 callback

  • Must 接受一个参数 db 实例,该实例表示正在运行事务的连接。

  • Must 不尝试提交、回滚或以其他方式管理事务。

  • May 不止一次地被召唤。

  • 应该 理想情况下只包含SQL操作。

此外,在调用此函数时,数据库不能有任何打开的事务,因为CRDB不支持嵌套事务。尝试这样做将引发一个 NotImplementedError .

最简单的例子:

def create_user(email):
    def callback(db_ref):
        return User.create(email=email)

    return db.run_transaction(callback, max_attempts=10)

user = create_user('huey@example.com')
class PooledCockroachDatabase(database[, **kwargs])

CockroachDB连接池实现,基于 PooledPostgresqlDatabase . 实现与相同的API CockroachDatabase ,但将执行客户端连接池。

run_transaction(db, callback[, max_attempts=None[, system_time=None[, priority=None]]])

在事务中运行SQL,并在客户端自动重试。看到了吗 CockroachDatabase.run_transaction() 有关详细信息。

参数:
  • db (CockroachDatabase) -- 数据库实例。

  • callback -- 可赎回的,接受单一 db 参数(与上面传递的值相同)。

备注

此函数等效于 CockroachDatabase 班级。

class UUIDKeyField

使用CRDB的UUID主键字段 gen_random_uuid() 函数自动填充初始值。

class RowIDField

使用CRDB的自动递增整数主键字段 unique_rowid() 函数自动填充初始值。

参见:

  • BinaryJSONField 从Postgresql扩展(在 cockroachdb 扩展模块,并别名为 JSONField

  • ArrayField 从Postgresql扩展。