Я попытался выполнить запрос с классом 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);
}
В чем причина этой ошибки? Я изучил предыдущие посты такого типа вопроса, но не нашел никаких решений.
Ваш ::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);
// ...
}
Вы создаете новый объект 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();
}
Лично я бы так и сделал.