SQLite PHP: Transaction

Summary: in this tutorial, we will show you how to use the transaction features of PHP PDO to ensure the data integrity in the SQLite database.

Let’s create a new table named task_documents that stores the relationships between a task and a document.

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
);Code language: SQL (Structured Query Language) (sql)

Basically, a task has multiple documents and a document may belong to many tasks. The relationship between a task and a document is many-to-many.

Whenever we add a new document to the documents table, we need to assign it to a specific task. We don’t want to be in a situation that a document is inserted without belonging to a task.

To ensure this, we must perform both actions: insert a new document and assign it to a task in the all-or-nothing fashion. To achieve this, we use the PDO transaction feature.

Whenever we execute a statement in PDO, the database commits the operation by default. To wrap multiple operations inside a transaction, we call the beginTransaction() method of the PDO object as follows:

$pdo->beginTransaction();Code language: PHP (php)

To commit the transaction, you call the commit() method:

$pdo->commit();Code language: PHP (php)

In case something wrong happened, you can roll back all the operations using the rollback() method as follows:

$pdo->rollback();Code language: PHP (php)

SQLite PHP transaction example

We create a new class name SQLiteTransaction for the demonstration.

The following method inserts a new document into the documents table and returns the document 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();
    }Code language: PHP (php)

The following method assigns a document to a task.

   /**
     * 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();
    }Code language: SQL (Structured Query Language) (sql)

The following method inserts a document and assigns it to a task within a single transaction.

    /**
     * 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;
        }
    }Code language: PHP (php)

Notice that you must execute the following statement to enable foreign key support in SQLite:

PRAGMA foreign_keys = ON;Code language: SQL (Structured Query Language) (sql)

Therefore, from the PHP application, we use the following statement:

$this->pdo->exec('PRAGMA foreign_keys = ON');Code language: PHP (php)

Let’s create the index.php file to test the SQLiteTransaction class.

<?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();
}Code language: PHP (php)

We assigned an non-existent task_id 9999 to purposely violate the foreign key constraint when assigning the document to the task. As the result, PHP threw a PDO exception that caused all operations to be rolled back.

Now, if you change the task id to any valid value in the tasks table, a new document will be inserted into the documents table and also new entry is also inserted into the task_documents table.

In this tutorial, we have shown you how to perform the transaction in SQLite using PHP PDO transaction API.

Was this tutorial helpful ?