开启两次事务,第一次事务未做任何操作,开启第一次事务,导致第二次事务任何操作未起任何作用。mysql隐式提交失效
DB::beginTransaction();
EmailRecord::where("send_status", EmailRecord::SEND_STATUS_WAIT)
->where("send_time", "<=", time())
->limit(100)
->lockForUpdate()
->get(["id", "email_id", "receive_email"])->toArray();
DB::table("email_system_send_records")
->whereIn("id", [9])
->update([
"send_status" => 5]);
DB::beginTransaction();
EmailSystemSendRecords::where("send_status", EmailSystemSendRecords::SEND_STATUS_WAIT)
->limit(100)
->lockForUpdate()
->get()->toArray();
DB::table("email_system_send_records")
->whereIn("id", [9])
->update([
"send_status" => EmailSystemSendRecords::SEND_STATUS_FINISH]);
DB::commit();
2. 问题分析
- mysql层面:事务的隐式提交。
事务隐式提交:在mysql中第一次事务开始时,未做提交操作,开启了第二次事务,第一次事务会自动提交。
在数据库中测试隐式提交,事务正常执行,第二次事务正常执行。 - 数据库版本问题
尝试了5.6,5.5,8.0版本,事务的隐式提交也是存在的,并出现第二次事务未做任何处理。 - Laravel底层对事务做了处理
vendorlaravelframeworksrcIlluminateDatabaseConcernsManagesTransactions.php
public function beginTransaction()
{
$this->createTransaction();
$this->transactions++;
optional($this->transactionsManager)->begin(
$this->getName(), $this->transactions
);
$this->fireConnectionEvent('beganTransaction');
}
public function commit()
{
if ($this->transactions == 1) {
$this->getPdo()->commit();
}
$this->transactions = max(0, $this->transactions - 1);
if ($this->transactions == 0) {
optional($this->transactionsManager)->commit($this->getName());
}
$this->fireConnectionEvent('committed');
}
3.结论
翻开了laravel源码对嵌套事务的处理,beginTransaction开启这个事务这个方法中,对未做提交或未做回滚的代码做了一个计数,当transactions 这个事务计数器大于1时,源码对嵌套事务做了暴力处理,所有事务都不提交,导致后续事务无法提交,导致mysql中的隐式提交失效。



