跳转到内容
简体中文

MariaDB

此内容尚不支持你的语言。

The MariaDB backend is the sibling of the Postgres backend for teams on MariaDB or MySQL. It provides the same three components — MariaDbJournal, MariaDbSnapshotStore, and MariaDbDurableStateStore — against a single database, via the official mariadb connector (which speaks both MariaDB and MySQL).

It’s a separate implementation from Postgres (not a shared dialect layer), so the SQL is idiomatic MariaDB, but the public contract and behaviour are identical.

mariadb is an optional peer dependency:

Terminal window
bun add mariadb

Lazy-imported on first use, like every other adapter.

import {
ActorSystem,
PersistenceExtensionId,
registerMariaDbPlugins,
} from 'actor-ts';
const system = new ActorSystem({
name: 'my-app',
config: `
actor-ts.persistence.journal.plugin = "actor-ts.persistence.journal.mariadb"
actor-ts.persistence.snapshot-store.plugin = "actor-ts.persistence.snapshot-store.mariadb"
`,
});
const ext = system.extension(PersistenceExtensionId);
const { durableStateStore } = registerMariaDbPlugins(ext, {
journal: { poolConfig: conn },
snapshotStore: { poolConfig: conn, keepN: 3 },
durableStateStore: { poolConfig: conn },
});
// conn = { host, port: 3306, user, password, database } — or pass a
// shared `pool` (from mariadb.createPool) at the top level to reuse one
// pool across all three, or a connection URL via `url`.

As with Postgres, the journal + snapshot store are selected by the config plugin IDs, and the durable-state store is returned for you to pass into your DurableStateActor settings.

interface MariaDbConnection {
url?: string; // mariadb://user:pass@host:3306/db
poolConfig?: Record<string, unknown>; // { host, port, user, password, database, … }
pool?: MariaDbPoolLike; // pre-built / shared pool
}
interface MariaDbJournalOptions extends MariaDbConnection {
eventsTable?: string; tagsTable?: string; autoCreateTables?: boolean;
}
interface MariaDbSnapshotStoreOptions extends MariaDbConnection {
snapshotsTable?: string; keepN?: number; autoCreateTables?: boolean;
}
interface MariaDbDurableStateStoreOptions extends MariaDbConnection {
table?: string; autoCreateTables?: boolean;
}

Discrete poolConfig (host/user/password/database) is the most portable way to connect; url and a pre-built pool are also accepted.

Same shape as Postgres, with MariaDB types — VARCHAR(255) ids, BIGINT sequence/revision/timestamp, LONGTEXT payloads — and indexes declared inline in CREATE TABLE (portable across MariaDB/MySQL versions, unlike CREATE INDEX IF NOT EXISTS):

CREATE TABLE events (
persistence_id VARCHAR(255) NOT NULL,
sequence_nr BIGINT NOT NULL,
payload LONGTEXT NOT NULL,
tags TEXT,
timestamp BIGINT NOT NULL,
PRIMARY KEY (persistence_id, sequence_nr),
INDEX idx_events_pid (persistence_id)
);
-- events_tags, snapshots, durable_state: as Postgres, with the types above

The behaviour is identical; the SQL differs:

OperationPostgresMariaDB
Placeholders$1, $2?
Tag dedup insertON CONFLICT DO NOTHINGINSERT IGNORE
Snapshot upsertON CONFLICT … DO UPDATEON DUPLICATE KEY UPDATE
keepN pruneNOT IN (SELECT … LIMIT)derived-table-wrapped subquery¹
Durable create conflictON CONFLICT DO NOTHING → rowCountplain INSERT, catch ER_DUP_ENTRY (1062)
Concurrency backstopSQLSTATE 23505ER_DUP_ENTRY / 1062

¹ MySQL/MariaDB reject LIMIT inside a bare IN (SELECT …) against the table being deleted, so the prune wraps the subquery in a derived table.

BIGINT may surface from the connector as a JS bigint; the backend coerces sequence/revision/timestamp to number at the mapping boundary.

  • PostgreSQL — the sibling backend, with the fuller walkthrough of registration + concurrency.
  • Cassandra journal — distributed, for scale-out.
  • Durable state — the state-oriented alternative to event sourcing.