我正在编写一个PHP函数,它将大量数据存储/更新到表中,这可能会导致死锁。我试图调查如何使用Doctrine重试失败的事务,但遗憾的是无法在线查找任何信息。我最终写了下面的代码
$retry = 0;
$done = false;
while (!$done and $retry < 3) {
try {
$this->entityManager->flush();
$done = true;
} catch (\Exception $e) {
sleep(1);
$retry++;
}
}
if ($retry == 3) {
throw new Exception(
"[Exception: MySQL Deadlock] Too many people accessing the server at the same time. Try again in few minutes"
);
}
我的问题:这种方法是否有可能在数据库中插入重复项?如果是这样,我怎么强迫Doctrine回滚交易呢?
答案 0 :(得分:13)
死锁返回错误1213,您应该在客户端处理
请注意,死锁和锁定等待是不同的事情。陷入僵局,没有“失败”的交易:他们都有罪。无法保证哪一个会被回滚。
您必须使用rollback
,您的样式代码将插入重复内容。例如,你应该:
$retry = 0;
$done = false;
$this->entityManager->getConnection()->beginTransaction(); // suspend auto-commit
while (!$done and $retry < 3) {
try {
$this->entityManager->flush();
$this->entityManager->getConnection()->commit(); // commit if succesfull
$done = true;
} catch (\Exception $e) {
$this->entityManager->getConnection()->rollback(); // transaction marked for rollback only
$retry++;
}
}
希望得到这个帮助。
答案 1 :(得分:1)
我正在处理使用Sf2.7和doctrine 2.4.7重试失败的事务:
use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\ORM\EntityManager;
class Foo
{
/**
* @var Registry
*/
protected $doctrine;
public function __construct(Registry $registry)
{
$this->doctrine = $registry;
}
protected function doSomething($entity, $attempt)
{
$em = $this->getEntityManager();
$conn = $em->getConnection();
try{
$conn->beginTransaction();
$entity->setBar("baz");
$em->flush();
$conn->commit();
} catch(\PDOException $e){
$conn->rollBack();
$attempt++;
if($attempt <= 3){
$this->doSomething($repayment, $attempt);
}
}
}
/**
* @return EntityManager
*/
protected function getEntityManager()
{
/** @var EntityManager $em */
$em = $this->doctrine->getManager();
if(!$em->isOpen()){
$this->doctrine->resetManager();
$em = $this->doctrine->getManager();
}
return $em;
}
}
答案 2 :(得分:1)
$connection = ...
$retry = 0;
$maxRetries = 3;
while ($retry < $maxRetries) {
try {
$connection->beginTransaction();
// do stuff
$connection->commit();
break;
} catch (Throwable $exception) {
$connection->rollBack();
$retry++;
if ($retry === $maxRetries) {
throw $exception;
}
}
}
有关Doctrine交易的更多信息,请访问https://www.doctrine-project.org/projects/doctrine-dbal/en/2.7/reference/transactions.html
只需注入Doctrine的EntityManager
(Interface
)或Connection
,例如。通过构造函数
<强>连接强>
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
或EntityManager
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
获取$this->entityManager->getConnection()
答案 3 :(得分:-3)
如果您没有使用ORM,那么使用它会自动管理死锁情况。