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

SSL 設定

在執行 Cockroach 叢集時,強烈建議使用 SSL 憑證。Psycopg2 支援開箱即用的 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 文件中找到。

Cockroach 擴充 API

playhouse.cockroachdb 擴充模組提供以下類別和輔助工具

使用 CRDB 時可能會有用的特殊欄位類型

  • UUIDKeyField - 主鍵欄位實作,使用 CRDB 的 UUID 類型,預設會隨機產生 UUID。

  • RowIDField - 主鍵欄位實作,使用 CRDB 的 INT 類型,預設為 unique_rowid()

  • JSONField - 與 Postgres 的 BinaryJSONField 相同,因為 CRDB 將 JSON 視為 JSONB。

  • ArrayField - 與 Postgres 擴充功能相同(但不支援多維陣列)。

CRDB 與 Postgres 的線路協定相容,並公開非常相似的 SQL 介面,因此可以使用 PostgresqlDatabase 與 CRDB,雖然不建議這麼做

  1. CRDB 不支援巢狀交易(儲存點),因此在使用 CockroachDatabase 時,已實作 atomic() 方法來強制執行此限制。如需更多資訊,請參閱 CRDB 交易

  2. CRDB 在欄位類型、日期函式和內省方面可能與 Postgres 有細微差異。

  3. CRDB 特有的功能由 CockroachDatabase 公開,例如指定交易優先順序或 AS OF SYSTEM TIME 子句。

CRDB 交易

CRDB 不支援巢狀交易(儲存點),因此如果遇到無效的巢狀結構,CockroachDatabase 上的 atomic() 方法已被修改為引發例外。如果您希望能夠巢狀使用交易程式碼,可以使用 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() 輔助工具。此輔助方法接受可呼叫的物件,該物件負責執行可能需要重試的任何交易陳述式。

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 API

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) – “low”、“normal” 或 “high” 其中之一。

傳回

傳回回呼傳回的值。

引發

如果超出 max_attempts,則會引發 ExceededMaxAttempts

在具有自動客戶端重試的交易中執行 SQL。

使用者提供的 callback

  • 必須接受一個參數,即代表交易正在執行的連線的 db 執行個體。

  • 不得嘗試提交、回滾或以其他方式管理交易。

  • 可以呼叫多次。

  • 理想情況下應該只包含 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。實作與 CockroachDatabase 相同的 API,但會進行客戶端連線集區。

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

在具有自動客戶端重試的交易中執行 SQL。有關詳細資訊,請參閱 CockroachDatabase.run_transaction()

參數
  • db (CockroachDatabase) – 資料庫實例。

  • callback – 可呼叫的物件,接受單一 db 參數 (其值會與上面傳入的值相同)。

注意

此函數等同於 CockroachDatabase 類別中名稱相同的同名方法。

class UUIDKeyField

UUID 主鍵欄位,使用 CRDB 的 gen_random_uuid() 函數自動填入初始值。

class RowIDField

自動遞增的整數主鍵欄位,使用 CRDB 的 unique_rowid() 函數自動填入初始值。

另請參閱

  • 來自 Postgresql 擴充功能的 BinaryJSONField (可在 cockroachdb 擴充模組中取得,並別名為 JSONField)。

  • 來自 Postgresql 擴充功能的 ArrayField