cybercog/php-db-locker

PHP application-level database locking mechanisms

Fund package maintenance!
paypal.me/antonkomarev

Installs: 24

Dependents: 0

Suggesters: 0

Security: 0

Stars: 7

Watchers: 1

Forks: 3

Open Issues: 1

pkg:composer/cybercog/php-db-locker


README

cog-php-db-locker

Releases License

Things to decide

  • Keep only PDO implementation, or make Doctrine/Eloquent drivers too?
  • Should callback for session lock be at the end of the params (after optional ones)?

Introduction

WARNING! This library is currently under development and may not be stable. Use in your services at your own risk.

PHP application-level database locking mechanisms to implement concurrency control patterns.

Supported drivers:

Installation

Pull in the package through Composer.

composer require cybercog/php-db-locker

Usage

Postgres

Transaction-level advisory lock

$dbConnection = new PDO($dsn, $username, $password);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$locker = new \Cog\DbLocker\Postgres\PostgresAdvisoryLocker();
$lockKey = \Cog\DbLocker\Postgres\PostgresLockKey::create(
    namespace: 'user',
    value: '4',
);

$dbConnection->beginTransaction();
$lock = $locker->acquireTransactionLevelLock(
    dbConnection: $dbConnection,
    key: $lockKey,
    timeoutDuration: \Cog\DbLocker\TimeoutDuration::zero(),
);
if ($lock->wasAcquired) {
    // Execute logic if lock was successful
} else {
    // Execute logic if lock acquisition has been failed
}
$dbConnection->commit();

Lock Key Creation

Create lock keys from human-readable identifiers:

// Auto-generated SQL comment: "[user:4]"
$lockKey = \Cog\DbLocker\Postgres\PostgresLockKey::create(
    namespace: 'user',
    value: '4',
);

// Custom SQL comment: "payment-processing[user:4]"
$lockKey = \Cog\DbLocker\Postgres\PostgresLockKey::create(
    namespace: 'user',
    value: '4',
    humanReadableValue: 'payment-processing',
);

Or from pre-computed int32 pairs (e.g., from external systems):

// Auto-generated SQL comment: "[42:100]"
$lockKey = \Cog\DbLocker\Postgres\PostgresLockKey::createFromInternalIds(
    classId: 42,
    objectId: 100,
);

// Custom SQL comment: "order:pending[42:100]"
$lockKey = \Cog\DbLocker\Postgres\PostgresLockKey::createFromInternalIds(
    classId: 42,
    objectId: 100,
    humanReadableValue: 'order:pending',
 );

The SQL comment appears in PostgreSQL logs for debugging and is automatically sanitized to prevent SQL injection.

Session-level advisory lock

Callback API

$dbConnection = new PDO($dsn, $username, $password);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$locker = new \Cog\DbLocker\Postgres\PostgresAdvisoryLocker();
$lockKey = \Cog\DbLocker\Postgres\PostgresLockKey::create(
    namespace: 'user',
    value: '4',
);

$payment = $locker->withinSessionLevelLock(
    dbConnection: $dbConnection,
    key: $lockKey,
    callback: function (
        \Cog\DbLocker\Postgres\LockHandle\SessionLevelLockHandle $lock, 
    ): Payment { // Define a type of $payment variable, so it will be resolved by analyzers
        if ($lock->wasAcquired) {
            // Execute logic if lock was successful
        } else {
            // Execute logic if lock acquisition has been failed
        }
    },
    timeoutDuration: \Cog\DbLocker\TimeoutDuration::zero(),
);

Low-level API

$dbConnection = new PDO($dsn, $username, $password);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$locker = new \Cog\DbLocker\Postgres\PostgresAdvisoryLocker();
$lockKey = \Cog\DbLocker\Postgres\PostgresLockKey::create(
    namespace: 'user',
    value: '4',
);

try {
    $lock = $locker->acquireSessionLevelLock(
        dbConnection: $dbConnection,
        key: $lockKey,
        timeoutDuration: \Cog\DbLocker\TimeoutDuration::zero(),
    );
    if ($lock->wasAcquired) {
        // Execute logic if lock was successful
    } else {
        // Execute logic if lock acquisition has been failed
    }
} finally {
    $lock->release();
}

Changelog

Detailed changes for each release are documented in the CHANGELOG.md.

License

🌟 Stargazers over time

Stargazers over time

About CyberCog

CyberCog is a Social Unity of enthusiasts. Research the best solutions in product & software development is our passion.

CyberCog