Service
Service 编排业务:只调 Repository,不在 Service 里直接查库(禁止 Db::)。继承 core\base\Service,用基类提供的事务方法,不要手写 beginTransaction / commit / rollBack。
事务与 afterCommit
runInTransaction(Closure $fn):统一事务入口。afterCommit(Closure $fn):在最外层事务真正提交后再执行;不在事务中则立即执行;事务回滚则丢弃。适合缓存失效、吊销 token 等「必须落库成功才做」的副作用。
php
use app\repository\user\UserRepository;
use core\auth\TokenVersion;
use core\base\Service;
use DI\Attribute\Inject;
class UserService extends Service
{
#[Inject]
protected UserRepository $userRepository;
public function changePassword(int $userId, string $old, string $new): bool
{
// …校验旧密码…
return $this->runInTransaction(function () use ($userId, $new): bool {
$ok = $this->userRepository->update($userId, [
'password' => password_hash($new, PASSWORD_DEFAULT),
]);
// 事务提交后再吊销,避免密码未改成功就先失效
$this->afterCommit(fn () => TokenVersion::bump($userId, 'user'));
return $ok;
});
}
}上例来自 app\service\user\UserService(依赖是 Repository;TokenVersion::bump 是核心辅助,不是另一个 Service)。AdminService 改密码后同样用 afterCommit 清会话缓存,保证事务提交后才吊销。
纪律
- 容器单例:实例属性只放注入的依赖,请求态放
support\Context。 - 涉及资金等关键事务时,
afterCommit回调应自带try/catch——回调抛错时库已经提交。