Skip to main content

SQLite PHP事务及其示例

让我们创建一个名为task_documents的新表,它存储任务和文档之间的关系。

CREATE TABLE IF NOT EXISTS task_documents (
task_id INT NOT NULL,
document_id INT NOT NULL,
FOREIGN KEY (
task_id
)
REFERENCES tasks (task_id) ON UPDATE CASCADE
ON DELETE CASCADE,
FOREIGN KEY (
document_id
)
REFERENCES documents (document_id) ON UPDATE CASCADE
ON DELETE CASCADE
);

基本上,一个任务有多个文档,一个文档可能属于多个任务。任务和文档之间的关系是多对多的。

每当我们向documents表中添加新文档时,我们都需要将其分配给特定的任务。我们不希望文档插入时不属于任务。

为了确保这一点,我们必须执行两个操作:插入一个新文档,并以全有或全无的方式将其分配给任务。为了实现这一点,我们使用PDO事务特性。

每当我们在PDO中执行一条语句时,默认情况下数据库会提交该操作。为了在一个事务中包装多个操作,我们调用PDO对象的beginTransaction()方法,如下所示:

$pdo->beginTransaction();

要提交事务,请调用commit()方法:

$pdo->commit();

如果发生错误,可以使用rollback()方法回滚所有操作,如下所示:

$pdo->rollback();

SQLite PHP事务示例

我们为演示创建了一个新的类名SQLiteTransaction。

以下方法将一个新文档插入documents表并返回文档id。

   /**
* Insert blob data into the documents table
* @param type $pathToFile
* @return document id
*/
public function insertDoc($mimeType, $pathToFile) {

$sql = "INSERT INTO documents(mime_type,doc) "
. "VALUES(:mime_type,:doc)";

// read data from the file
$fh = fopen($pathToFile, 'rb');

$stmt = $this->pdo->prepare($sql);

// pass values
$stmt->bindParam(':mime_type', $mimeType);
$stmt->bindParam(':doc', $fh, \PDO::PARAM_LOB);

// execute the INSERT statement
$stmt->execute();

fclose($fh);

// return the document id
return $this->pdo->lastInsertId();
}

以下方法将文档分配给任务。

   /**
* Assign a document to a task
* @param int $taskId
* @param int $documentId
*/
private function assignDocToTask($taskId, $documentId) {
$sql = "INSERT INTO task_documents(task_id,document_id) "
. "VALUES(:task_id,:document_id)";

$stmt = $this->pdo->prepare($sql);

$stmt->bindParam(':task_id', $taskId);
$stmt->bindParam(':document_id', $documentId);

$stmt->execute();
}

以下方法插入文档并将其分配给单个事务中的任务。

    /**
* Add a task and associate a document to it
* @param int $taskId
* @param string $mimeType
* @param string $pathToFile
*/
public function attachDocToTask($taskId, $mimeType, $pathToFile) {
try {

// to make sure the foreign key constraint is ON
$this->pdo->exec('PRAGMA foreign_keys = ON');

// begin the transaction
$this->pdo->beginTransaction();

// insert a document first
$documentId = $this->insertDoc($mimeType, $pathToFile);

// associate document with the task
$this->assignDocToTask($taskId, $documentId);

// commit update
$this->pdo->commit();
} catch (\PDOException $e) {
// rollback update
$this->pdo->rollback();
//
throw $e;
}
}

请注意,必须执行以下语句才能在SQLite中启用外键支持:

PRAGMA foreign_keys = ON;

因此,在PHP应用程序中,我们使用以下语句:

$this->pdo->exec('PRAGMA foreign_keys = ON');

让我们创建索引。php文件来测试SQLiteTransaction类。

<?php

require 'vendor/autoload.php';

use App\SQLiteConnection;
use App\SQLiteTransaction;

$pdo = (new SQLiteConnection())->connect();
$sqlite = new SQLiteTransaction($pdo);

$taskId = 9999;

try {
// add a new task and associate a document
$sqlite->attachDocToTask($taskId, 'application/pdf', 'assets/test.pdf');
} catch (PDOException $e) {
echo $e->getMessage();
}

我们分配了一个不存在的任务_id9999,以便在将文档分配给任务时故意违反外键约束。结果,PHP抛出了一个PDO异常,导致所有操作回滚。

现在,如果将task id更改为tasks表中的任何有效值,则会在documents表中插入一个新文档,并在task_documents表中插入一个新条目。

在本教程中,我们向您展示了如何使用PHP PDO事务API在SQLite中执行事务。