/**
* 创建一个用户和用户的关联数据
* @param array $userData
* @param array $userFinanceData
* @return UserModel
* @throws \Exception
*/
public function register($userData, $userFinanceData)
{
$db = UserModel::query()->getConnection();
try{
$db->beginTransaction();
$user = UserModel::create($userData);
$userFinanceData['user_id'] = $user->id;
FinanceAccountModel::create($userFinanceData);
// 事件触发放在这里 1 ?
$db->commit();
}catch (\Exception $exception){
$db->rollBack();
throw $exception;
}
// 事件触发放在这里 2 ?
event(new UserCreatedEvent($user));
return $user;
}
如果放在[1]处,那么如果数据库事务提交失败,事件却发出去了。导致事件消费者取不到该用户的数据。
如果放在[2]处,那么如果事件触发失败(例如redis连接错误),用户却创建成功了,但是创建用户后需要做的一些事情没有做,导致用户数据不完整。
怎么做才好?
这种问题,你没法避免的,分布式事务的问题。
有一种可以参考下
你在数据库表里面建立一个事件表,就是要发的事件,随事务一起提交。提交完后,你再去发了,发完记得在数据库的记录上做一个标记了,一个状态是新建未发送,一个是已发送。另外,还得有一个线程池去扫那个表,去发那些发失败的。
接受事件的地方,还得做幂等。
如果要更可靠的话,事件表的标记在加一个已处理,
反正要就是比较麻烦了,要考虑的很多