sbooker/transaction-manager

应用于应用层事务控制的抽象。

2.3.1 2024-02-06 15:44 UTC

README

应用于应用层事务控制的抽象。

Latest Version Software License PHP Version Total Downloads Build Status codecov

安装

composer require sbooker/transaction-manager

使用示例

use Sbooker\TransactionManager\TransactionHandler;
use Sbooker\TransactionManager\TransactionManager;


$transactionManager = new TransactionManager(new class implements TransactionHandler { ... });

class Entity {
    /**
     * @throws \Exception 
     */  
    public function update(): void { ... }
}

示例 1. 创建实体

$transactionManager->transactional(function () use ($transactionManager) {
    $transactionManager->persist(new Entity());
});

示例 2. 仅使用TransactionManager更新实体

$transactionManager->transactional(function () use ($transactionManager, $entityId) {
    $entity = $transactionManager->getLocked(Entity::class, $entityId);
    $entity->update(); // if exception throws, transaction will be rolled back
});

示例 3. 使用仓库更新实体

$transactionManager->transactional(function () use ($transactionManager, $entityRepository, $criteria) {
    $entity = $entityRepository->getLocked($criteria);
    $entity->update(); // if exception throws, transaction will be rolled back
    $transactionManager->save($entity);
});

示例 4. 支持嵌套事务

通常,您只需要一个事务来处理单个命令(请参阅之前的示例)。通常,您在应用层服务(所谓命令处理器)中这样做。

final class CommandProcessor {
    private TransactionManager $transactionManager;
    ...
    /** @throws \Exception */
    public function update($entityId): void
    {
        $transactionManager->transactional(function () use ($transactionManager, $entityId) {
            $entity = $transactionManager->getLocked(Entity::class, $entityId);
            $entity->update(); 
        });
    }
}

当您同步地从表现层调用应用层时,它运行良好。例如,使用HTTP请求并在控制器中将它转换为命令。

但有时您需要处理与HTTP请求相同的域逻辑之前存储的命令。当然,在这种情况下,您想要保存命令执行结果。例如,如果执行失败,则进行下一次重试。在这种情况下,您需要嵌套事务,并且外层事务将不会回滚。

$commandProcessor = new CommandProcessor($transactionManager);

$transactionManager->transactional(function () use ($transactionManager, $commandId, $commandProcessor) {
    $command = $transactionManager->getLocked(Command::class, $commandId);
   try {
        $commandProcessor->update($command->getEntityId());
        $command->setSuccessExecutionState();
   } catch (\Exception) {
        $command->setFailExecutionState(); 
   }
});

注意!

$entityId = ...;
$transactionManager->transactional(function () use ($transactionManager, $entityId) {
    $entity = new SomeEntity($entityId);
    $transactionManager->persist($entity);
    
    // Depends on TransactionHandler implementation $persistedEntity may be null in same transaction with persist
    $persistedEntity = $transactionManager->getLocked($entityId);    
}

许可证

请参阅LICENSE文件。