mysql — PHP PDO Нет активной транзакции

Я попытался выполнить запрос с классом PDO и получил это сообщение об ошибке: "There is no active transaction" при попытке совершить.

Вот мой код:

  public function runExQuery($sql) {
$preparedQuery = $this->connect()->prepare($sql);
$this->connect()->beginTransaction();
$preparedQuery->execute();
$this->connect()->commit();
}



private function connect() {
return new PDO('mysql:host=' . $this->host . ';dbname=' . $this->database . '', $this->username, $this->password);
}

В чем причина этой ошибки? Я изучил предыдущие посты такого типа вопроса, но не нашел никаких решений.

1

Решение

Ваш ::connect() Метод создает новый PDO каждый раз, когда вы вызываете его.

Поскольку транзакции не сохраняются вне соединений, повторное соединение стирает их.

Чтобы исправить это, сохраните объект PDO как свойство класса:

class MyPdoClass
{
private $pdo;
// ...

public function connect()
{
if ($this->pdo instanceof PDO) {
return;
}
$this->pdo = new PDO(// ....
}

а затем сослаться на него после вызова connect:

//...
public function runExQuery($query)
{
$this->connect();
$this->pdo->prepare($query);
// ...
}
3

Другие решения

Вы создаете новый объект PDO каждый раз, когда звоните $this->connect()так что если у вас есть:

$stmt1 = $this->connect()->prepare(" ... ");
$stmt2 = $this->connect()->prepare(" ... ");

$stmt1 а также $stmt2 фактически будут совершенно разными объектами PDO, поэтому, если вы начнете транзакцию с одним объектом, он НЕ будет применяться к другому. Вместо этого вы должны сохранить объект PDO и ссылаться на него, вместо того, чтобы каждый раз создавать новый.

В большинстве случаев мне проще передать это конструктору класса, однако, если вы хотите сделать минимальное редактирование, вы можете просто сделать:

class YourClass {
private $dbh;
private function connect() {
if (!isset($this->dbh)) {
$this->dbh = new PDO('mysql:host=' . $this->host . ';dbname=' . $this->database, $this->username, $this->password);
}
return $this->dbh;
}
}

Однако вы можете изменить имя connect() к чему-то более логичному, как getDbh(),

Если вместо этого вы хотите поместить его в конструктор объекта, вы можете сделать это:

class YourClass {
private $dbh;
public function __construct(PDO $dbh) {
$this->dbh = $dbh;
}
}

$dbh = new PDO('mysql:host=' . $host . ';dbname=' . $database, $username, $password);
$yourclass = new YourClass($dbh);

Тогда в любом другом методе класса вы просто $this->dbh, Используя ваш код в качестве примера:

public function runExQuery($sql) {
$preparedQuery = $this->dbh->prepare($sql);
$this->dbh->beginTransaction();
$preparedQuery->execute();
$this->dbh->commit();
}

Лично я бы так и сделал.

2

По вопросам рекламы [email protected]