Shopware 6存储库的数据库事务?

huangapple go评论86阅读模式
英文:

Shopware 6 database transactions for repositories?

问题

In Shopware 6,我们已经实现了一个可以与多个数据库表一起工作的优惠券插件。为了避免竞态条件或不一致的数据,最好使用数据库事务。

在与多个实体仓库一起工作时,如何执行此操作?

在SQL级别上,应该类似于以下内容:

begin;
SELECT code FROM voucher_pool;
INSERT INTO voucher_code (code, active, value, valid_until) VALUES ('ABCDEF', 1, 20, '2025-01-01');
INSERT INTO voucher_code_transaction (code_id, value) VALUES (X'...', +20);
UPDATE voucher_pool SET redeemed=1 WHERE code='ABCDEF';
commit;

在Shopware级别上,voucher_codevoucher_code_transaction 可以作为一个请求使用。但是我们不确定如何将 voucher_pool 表添加到同一个事务中。应该如下所示:

// 开始事务
try {
    $availableCode = $this->voucherPoolRepository->search($criteria, $context)->first();
    $this->voucherCodeRepository->upsert([
        [
            'code'         => $availableCode->getCode(),
            'active'       => true,
            'value'        => 20,
            'valid_until'  => '2025-01-01',
            'transactions' => [
                [
                    'value' => 20,
                ],
            ],
        ],
    ], $context);
    $this->voucherPoolRepository->update([
        [
            'id'       => $availableCode->getId(),
            'redeemed' => true,
        ],
    ], $context);

    // 提交事务
} catch (Throwable) {
    // 回滚事务
}

在其他购物系统中,比如Magento,有一个事务对象,您可以将对象添加到其中,以触发一次联合保存。在Shopware 6中是否有类似的东西?还是只能使用Doctrine的Connection对象来执行事务?

例如:

/** @var \Doctrine\DBAL\Connection $connection */
$connection->beginTransaction();
$this->voucherCodeRepository->upsert(...);
$this->voucherPoolRepository->update(...);
$connection->commit();
英文:

In Shopware 6 we have implemented a voucher plugin that works with several database tables. To avoid race conditions or inconsistent data, it would make sense to use database transactions.

How can we do this when working with multiple entity repositories?

At SQL level it should look something like this:

begin;
SELECT code FROM voucher_pool;
INSERT INTO voucher_code (code, active, value, valid_until) VALUES ('ABCDEF', 1, 20, '2025-01-01');
INSERT INTO voucher_code_transaction (code_id, value) VALUES (X'...', +20);
UPDATE voucher_pool SET redeemed=1 WHERE code='ABCDEF';
commit;

At Shopware level, voucher_code and voucher_code_transaction can be used as one request. But we are not sure how to add the voucher_pool table to the same transaction. It should look like this:

// begin transaction
try {
    $availableCode = $this->voucherPoolRepository->search($criteria, $context)->first();
    $this->voucherCodeRepository->upsert([
        [
            'code'         => $availableCode->getCode(),
            'active'       => true,
            'value'        => 20,
            'valid_until'  => '2025-01-01',
            'transactions' => [
                [
                    'value' => 20,
                ],
            ],
        ],
    ], $context);
    $this->voucherPoolRepository->update([
        [
            'id'       => $availableCode->getId(),
            'redeemed' => true,
        ],
    ], $context);

    // commit
} catch (Throwable) {
    // rollback
}

In other shop systems, such as Magento, there is a transaction object to which you can add objects to trigger a combined save at once. Is there something like this in Shopware 6? Or are transactions only possible with the Connection object from Doctrine?
e.g.

/** @var \Doctrine\DBAL\Connection $connection */
$connection->beginTransaction();
$this->voucherCodeRepository->upsert(...);
$this->voucherPoolRepository->update(...);
$connection->commit();

答案1

得分: 1

你可以使用 SyncService 来合并不同实体的多个写操作。

use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\Api\Sync\SyncBehavior;
use Shopware\Core\Framework\Api\Sync\SyncOperation;
use Shopware\Core\Framework\Api\Sync\SyncService;

$this->container->get(SyncService::class)->sync([
    new SyncOperation(
        'write',
        VoucherCodeDefinition::ENTITY_NAME,
        SyncOperation::ACTION_UPSERT,
        $codePayload
    ),
    new SyncOperation(
        'write',
        VoucherPoolDefinition::ENTITY_NAME,
        SyncOperation::ACTION_UPSERT,
        $poolPayload
    ),
], Context::createDefaultContext(), new SyncBehavior());
英文:

You can combine multiple write operations of different entities using the SyncService.

use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\Api\Sync\SyncBehavior;
use Shopware\Core\Framework\Api\Sync\SyncOperation;
use Shopware\Core\Framework\Api\Sync\SyncService;

$this->container->get(SyncService::class)->sync([
    new SyncOperation(
        'write',
        VoucherCodeDefinition::ENTITY_NAME,
        SyncOperation::ACTION_UPSERT,
        $codePayload
    ),
    new SyncOperation(
        'write',
        VoucherPoolDefinition::ENTITY_NAME,
        SyncOperation::ACTION_UPSERT,
        $poolPayload
    ),
], Context::createDefaultContext(), new SyncBehavior());

huangapple
  • 本文由 发表于 2023年5月17日 20:10:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76271954.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定