Verwandte Lernempfehlungen:
MySQL-Tutorial Eine Ansichtsvorlage, die sogenannte vorbereitete Anweisung, ist eine vordefinierte SQL-Anweisungsvorlage, in der die spezifischen Parameterwerte durch Platzhalter ersetzt werden:
INSERT INTO REGISTRY (name, value) VALUES (?, ?) INSERT INTO REGISTRY (name, value) VALUES (:name, :value)
Beispielcode hinzufügen, löschen, ändern und abfragenAls nächstes implementieren wir die Vorgänge zum Hinzufügen, Löschen, Ändern und Abfragen der MySQL-Datenbank basierend auf der von PDO bereitgestellten vorbereiteten Anweisungs-API. Wir werden sie objektorientiert implementieren :Warum sich all diese Mühe machen? Wäre es nicht schön, die zuvor gezeigte
query
-Methode direkt zu verwenden, um Hinzufügungs-, Lösch-, Änderungs- und Abfragevorgänge durchzuführen? Lassen Sie uns als Nächstes über die Vorteile vorbereiteter Anweisungen sprechen oder darüber, warum wir vorbereitete Anweisungen für die Datenbankinteraktion verwenden sollten. Es gibt zwei Vorteile:Zusammenfassend wird aus Sicht der Leistung und Sicherheit empfohlen, vorbereitete Anweisungen zu verwenden, um Vorgänge zum Hinzufügen, Löschen, Ändern und Abfragen in der Datenbank abzuwickeln.
- Zuallererst verwendet die im Voraus definierte SQL-Vorlage nur vorbereitete Anweisungen wird einmal analysiert, kann aber durch Übergabe unterschiedlicher Parameterwerte mehrmals ausgeführt werden, wodurch eine wiederholte Analyse, Kompilierung und Optimierung von SQL-Anweisungen mit derselben Vorlage vermieden und die Ausführungsgeschwindigkeit von Datenbankoperationen verbessert wird.
- Zweitens; Anschließend wird es an die Vorverarbeitung übergeben. Die Parameterwerte der Anweisung werden vom zugrunde liegenden Treiber verarbeitet, wodurch SQL-Injection-Angriffe wirksam vermieden werden.
<?php class Post { public $id; public $title; public $content; public $created_at; /** * @var PDO */ protected $pdo; public function __construct(PDO $pdo = null) { if ($pdo != null) { $this->pdo = $pdo; } } public function insert($title, $content) { $sql = 'INSERT INTO `post` (title, content, created_at) VALUES (:title, :content, :created_at)'; try { // 准备预处理语句 $stmt = $this->pdo->prepare($sql); // 获取当前时间对应的格式化字符串:2020-05-28 13:00:00 $datetime = date('Y-m-d H:i:s', time()); // 绑定参数值 $stmt->bindParam(':title', $title, PDO::PARAM_STR); $stmt->bindParam(':content', $content, PDO::PARAM_STR); $stmt->bindParam(':created_at', $datetime, PDO::PARAM_STR); // 执行语句 $stmt->execute(); return $this->pdo->lastInsertId(); // 返回插入记录对应ID } catch (PDOException $e) { printf("数据库插入失败: %s\n", $e->getMessage()); } } public function select($id) { $sql = 'SELECT * FROM `post` WHERE id = ?'; try { // 准备预处理语句 $stmt = $this->pdo->prepare($sql); // 绑定参数值 $stmt->bindValue(1, $id, PDO::PARAM_INT); // 执行语句 $stmt->execute(); return $stmt->fetchObject(self::class); // 以对象方式返回结果集 } catch (PDOException $e) { printf("数据库查询失败: %s\n", $e->getMessage()); } } public function selectAll() { $sql = 'SELECT * FROM `post` ORDER BY id DESC'; try { // 准备预处理语句 $stmt = $this->pdo->prepare($sql); // 执行语句 $stmt->execute(); return $stmt->fetchAll(); // 返回所有结果集 } catch (PDOException $e) { printf("数据库查询失败: %s\n", $e->getMessage()); } } public function update($id) { $sql = 'UPDATE `post` SET created_at = :created_at WHERE id = :id'; try { // 准备预处理语句 $stmt = $this->pdo->prepare($sql); $datetime = date('Y-m-d H:i:s', time()); // 绑定参数值 $stmt->bindParam(':created_at', $datetime, PDO::PARAM_STR); $stmt->bindValue(':id', $id, PDO::PARAM_INT); // 执行语句 $stmt->execute(); return $stmt->rowCount(); } catch (PDOException $e) { printf("数据库更新失败: %s\n", $e->getMessage()); } } public function delete($id) { $sql = 'DELETE FROM `post` WHERE id = ?'; try { // 准备预处理语句 $stmt = $this->pdo->prepare($sql); // 绑定参数值 $stmt->bindValue(1, $id, PDO::PARAM_INT); // 执行语句 $stmt->execute(); return $stmt->rowCount(); } catch (PDOException $e) { printf("数据库删除失败: %s\n", $e->getMessage()); } } }
Post
-Klasse erstellt und dann die $pdo
-Instanz im Konstruktor initialisiert (von außen übergeben) und dann das Hinzufügen, Löschen, Änderungs- und Abfrageoperationen basierend auf vorbereiteten Anweisungen in die entsprechenden Klassenmethoden. Die Gesamtlogik ist sehr einfach. Zuerst wird die SQL-Vorlage über die Prepare-Methode des PDO-Objekts übergeben. Diese Methode gibt das PDOStatement-Objekt zurück , wird die bindParam-Methode des Objekts aufgerufen. Der erste Parameter dieser Methode ist der Platzhalter, der zweite Parameter ist der Parameterwert und der dritte Parameter ist der Werttyp (die entsprechende Konstante kann abgefragt werden). (die vordefinierte PDO-Konstante). Binden Sie sie. Nach der Übergabe der Parameter können Sie die Ausführungsmethode des PDOStatement-Objekts aufrufen, um die vorbereitete Anweisung auszuführen. Für Einfügevorgänge können Sie die lastInsertId-Methode für das PDO-Objekt verwenden, um die Primärschlüssel-ID des eingefügten Datensatzes zurückzugeben. Für Aktualisierungs- und Löschmethoden können Sie die rowCount-Methode für das PDOStatement-Objekt verwenden, um die Anzahl der betroffenen Zeilen zurückzugeben um anzuzeigen, ob der Vorgang erfolgreich war. Für Abfragevorgänge können Sie einen einzelnen Datensatz über die fetch-Methode des PDOStatement-Objekts zurückgeben oder die fetchObject-Methode verwenden, um eine Objektinstanz zurückzugeben, die einer bestimmten Klasse zugeordnet ist (auch ein einzelner Datensatz). Bei mehreren Ergebnissen können Sie zurückgeben es über die fetchAll-Methode. Es ist zu beachten, dass Sie beim Deklarieren vorbereiteter Anweisungen den Platzhalter ?
oder :name
verwenden können, der einen besser lesbaren Platzhalter darstellt, und dann wann Für die Bindungsparameter können Sie entweder die bindValue- oder die bindParam-Methode verwenden. Die in beiden übergebenen Parameter sind dieselben, aber für den Platzhalter ?
müssen Sie über die numerische Sequenz eine Zuordnung zur SQL-Vorlage herstellen Nummer (beginnend mit 1). query
方法进行增删改查操作它不香吗?呃,那我们接下来来说说预处理语句的好处,或者说为什么要使用预处理语句进行数据库交互,好处有二:
综上,从性能和安全角度考虑,推荐使用预处理语句处理数据库的增删改查操作。
接下来,我们基于 PDO 提供的预处理语句 API 实现 MySQL 数据库的增删改查操作,我们将通过面向对象的方式来实现:
// 初始化 PDO 连接实例 $dsn = 'mysql:host=127.0.0.1;port=3306;dbname=test;charset=utf8mb4'; $user = 'root'; $pass = 'root'; try { $pdo = new PDO($dsn, $user, $pass); } catch (PDOException $e) { printf("数据库连接失败: %s\n", $e->getMessage()); } // 测试代码 $post = new Post($pdo); // insert $title = '这是一篇测试文章'; $content = '测试内容: 今天天气不错'; $id = $post->insert($title, $content); echo '文章插入成功: ' . $id . '<br>'; // select $item = $post->select($id); echo '<pre class="brush:php;toolbar:false">'; print_r($item); // update $affected = $post->update($id); echo '受影响的行数: ' . $affected . '<br>'; // delete $affected = $post->delete($id); echo '受影响的行数: ' . $affected . '<br>'; // selectAll $items = $post->selectAll(); print_r($items);
我们构建了一个 Post
类,然后在构造函数中初始化 $pdo
实例(从外部传入),然后将基于预处理语句实现的增删改查操作分解到对应的类方法中。整体逻辑非常简单,以 insert
为例,首先通过 PDO 对象的 prepare 方法传入 SQL 模板构建预处理语句,该方法返回 PDOStatement 对象,接下来,就是调用该对像的 bindParam 方法绑定具体参数值,该方法的第一个参数是占位符,第二个参数是参数值,第三个参数是值类型(对应的常量可以在 PDO 预定义常量中查询),绑定好参数后,就可以调用 PDOStatement 对象的 execute 方法执行预处理语句了。
对于插入操作,可以通过 PDO 对象上的 lastInsertId 方法返回插入记录的主键 ID,对于更新和删除方法,可以通过 PDOStatement 对象上的 rowCount 方法返回受影响行数表示是否操作成功。对于查询操作,可以通过 PDOStatement 对象的 fetch 方法返回单条记录,也可以通过 fetchObject 方法返回映射到指定类后的对象实例(也是单条记录),对于多个结果,可以通过 fetchAll 方法返回。
需要注意的是,在声明预处理语句的时候,可以通过 ?
占位符,也可以通过 :name
这种可读性更好的占位符,然后在绑定参数时,既可以通过 bindValue 也可以通过 bindParam 方法,两者传递参数一样,只是对于 ?
占位符,需要通过数值序号建立与 SQL 模板的映射(从 1 开始)。
结合代码和 PHP 官方文档理解上面的代码并不困难,接下来,我们来编写测试代码:
return $stmt->fetchAll(PDO::FETCH_CLASS, self::class);
初始化一个 PDO 对象实例传入 Post
构造函数,然后依次调用 Post 对象的增删改查方法。在浏览器中访问,打印结果如下:
我们可以看到 fetchAll
方法默认返回的结果集数组中既包含索引映射,又包含字段名映射,这可以通过设置获取模式来解决,比如要返回 Post
对象数组,可以这么做:
public function batchInsert(array $items) { $sql = 'INSERT INTO `post` (title, content, created_at) VALUES (:title, :content, :created_at)'; try { // 开启事务 $this->pdo->beginTransaction(); // 准备预处理语句 $stmt = $this->pdo->prepare($sql); foreach ($items as $item) { // 绑定参数值 $datetime = date('Y-m-d H:i:s', time()); $stmt->bindParam(':title', $item->title, PDO::PARAM_STR); $stmt->bindParam(':content', $item->content, PDO::PARAM_STR); $stmt->bindParam(':created_at', $datetime, PDO::PARAM_STR); // 执行语句 $stmt->execute(); } $this->pdo->commit(); // 提交事务 return $stmt->rowCount(); // 返回受影响的行数 } catch (PDOException $e) { $this->pdo->rollBack(); // 回滚事务 printf("数据库批量插入失败: %s\n", $e->getMessage()); } }
这样,返回的结果就是这样的了:
更多模式设置,请参考官方文档中 fetchAll 方法的介绍和示例。
最后,我们再来看看如何通过 PDO 扩展实现数据库事务的提交和回滚,我们已经知道,对于单条 SQL 语句而言,事务提交和回滚是自动完成的,对于 SQL 语句序列(多条 SQL 语句),则需要显式开启事务和提交事务,PDO 对象也为此提供了对应的 API 方法。非常简单,比如我们在 Post
类中新增一个批量插入方法 batchInsert
Es ist nicht schwer, den obigen Code zu verstehen, indem wir den Code und die offizielle PHP-Dokumentation kombinieren. Als nächstes schreiben wir den Testcode:
$post = new Post($pdo); $items = [ [ 'title' => '这是一篇测试文章111', 'content' => '测试内容' ], [ 'title' => '这是一篇测试文章222', 'content' => '测试内容' ], [ 'title' => '这是一篇测试文章333', 'content' => '测试内容' ], ]; $post->batchInsert($items); $items = $post->selectAll(); print_r($items);
Post
-Konstruktor , und dann aufrufen Post nacheinander Methoden zum Hinzufügen, Löschen, Ändern und Abfragen von Objekten. Greifen Sie im Browser darauf zu und drucken Sie das Ergebnis wie folgt aus: 🎜🎜🎜🎜Wir können sehen, dass das von der fetchAll
-Methode zurückgegebene Ergebnismengenarray standardmäßig sowohl Indexzuordnung als auch Feldnamenzuordnung enthält. Dies kann durch Festlegen des Abrufmodus, z. B. durch die Rückgabe von Post Für ein Objektarray können Sie Folgendes tun: 🎜rrreee🎜Auf diese Weise sieht das zurückgegebene Ergebnis wie folgt aus: 🎜🎜🎜🎜Weitere Moduseinstellungen finden Sie in der Einführung und den Beispielen der fetchAll-Methode in der offiziellen Dokumentation. 🎜🎜Datenbanktransaktionen🎜🎜Abschließend schauen wir uns an, wie die Übermittlung und das Rollback von Datenbanktransaktionen durch die PDO-Erweiterung implementiert werden. Wir wissen bereits, dass die Übermittlung und das Rollback von Transaktionen für eine einzelne SQL-Anweisung automatisch abgeschlossen werden, und für eine Folge von SQL-Anweisungen (Mehrere SQL-Anweisungen), Sie müssen die Transaktion explizit starten und senden. Das PDO-Objekt stellt hierfür auch entsprechende API-Methoden bereit. Es ist ganz einfach. Wir fügen zum Beispiel eine Batch-Einfügemethode batchInsert
in der Klasse Post
hinzu: 🎜public function batchInsert(array $items) { $sql = 'INSERT INTO `post` (title, content, created_at) VALUES (:title, :content, :created_at)'; try { // 开启事务 $this->pdo->beginTransaction(); // 准备预处理语句 $stmt = $this->pdo->prepare($sql); foreach ($items as $item) { // 绑定参数值 $datetime = date('Y-m-d H:i:s', time()); $stmt->bindParam(':title', $item->title, PDO::PARAM_STR); $stmt->bindParam(':content', $item->content, PDO::PARAM_STR); $stmt->bindParam(':created_at', $datetime, PDO::PARAM_STR); // 执行语句 $stmt->execute(); } $this->pdo->commit(); // 提交事务 return $stmt->rowCount(); // 返回受影响的行数 } catch (PDOException $e) { $this->pdo->rollBack(); // 回滚事务 printf("数据库批量插入失败: %s\n", $e->getMessage()); } }
我们只需要在执行 SQL 序列之前调用 PDO 对象的 beginTransaction 方法开启事务,然后在所有 SQL 语句执行完成后调用 commit 方法提交事务,如果 SQL 执行过程中出错,则在异常处理代码中通过 PDO 对象的 rollBack 方法回滚事务。
为上述方法编写测试代码:
$post = new Post($pdo); $items = [ [ 'title' => '这是一篇测试文章111', 'content' => '测试内容' ], [ 'title' => '这是一篇测试文章222', 'content' => '测试内容' ], [ 'title' => '这是一篇测试文章333', 'content' => '测试内容' ], ]; $post->batchInsert($items); $items = $post->selectAll(); print_r($items);
执行这段代码,打印结果中包含新插入的文章数据,则表明事务提交成功:
关于通过 PDO 扩展与 MySQL 数据库交互,我们就简单介绍到这里,更多细节可以阅读官方文档,相信通过这几个课程的学习,你已经对 MySQL 数据库的基本使用以及如何在 PHP 中连接数据库并进行增删改查有了初步的认知,从下篇教程开始,我们将结合具体实战项目来开发一个现代的 PHP 项目,将之前的学习到的知识点应用到实战中,并且引入一些现代的 PHP 理念对项目进行管理。
想了解更多相关文章,敬请关注php mysql栏目!
Das obige ist der detaillierte Inhalt vonInteragieren Sie mit der MySQL-Datenbank über die PDO-Erweiterung, um Hinzufügung, Löschung, Änderung und Abfrageimplementierung sowie Datenbanktransaktionen zu implementieren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!