Transaktionen

Sollen mehrere Abfragen gebündelt an den Datenbankserver übertragen werden und sollen bei einem Fehler die Anweisugen nicht ausgeführt werden, so kommen Transaktionen zum Einsatz. In dem folgenden Beispiel wird die Verwendung von Transaktionen exemplarisch dargestellt.

/**
 * Datenquelle/DataSource erstellen
 */
$dsn=new \Alvine\Persistence\Provider\MySQL\DataSource
    ($host, $port, $database, $table, $user, $password, $parameter);
/**
 * Datenobjekt mit der Verbindung zum Datenbankserver
 */
$dataObject=new \Alvine\Persistence\Relation\DataObject
    ($dsn, new \Alvine\Types\Map\SimpleMap());


/*
 * Gebündelte Statements
 */
$transaction=new \Alvine\Persistence\Relation\Transaction(true);

/** Erstes Statement */
$records=new \Alvine\Persistence\Relation\Records();

$records->append(new \Alvine\Persistence\Relation\Record(
    ['ISBN'=>'111-1-86681-001-6', 'book-count'=>'10',
    'title'=>'My Title 10', 'record'=>(string) 
        new \Alvine\Date\Date(2017, 12, 31)]));
$records->append(new \Alvine\Persistence\Relation\Record(
    ['ISBN'=>'222-2-86681-001-6', 'book-count'=>'20',
    'title'=>'My Title 20', 'record'=>(string) 
        new \Alvine\Date\Date(2017, 12, 31)]));

$insertStatement=new \Alvine\Persistence\Relation\SQL\Insert\DefinedStatement(
    \Alvine\Persistence\Relation\Definition::getInstanceFromArray([
        ['example-1', 'ISBN'],
        ['example-1', 'title'],
        ['example-1', 'record', '\Alvine\Persistence\Relation\Field\Date'],
        ['example-1', 'book-count', '\Alvine\Persistence\Relation\Field\Integer'],
    ]));
$transaction->append(new \Alvine\Persistence\Relation\Query
    ($insertStatement, $records));

/** Zweites Statement */
$records=new \Alvine\Persistence\Relation\Records();

$records->append(new \Alvine\Persistence\Relation\Record(
    ['ISBN'=>'111-1-86681-001-6', 'book-count'=>'11']));
$records->append(new \Alvine\Persistence\Relation\Record(
    ['ISBN'=>'222-2-86681-001-6', 'book-count'=>'22']));

$updateStatement=new \Alvine\Persistence\Relation\SQL\Update\DefinedStatement(
    \Alvine\Persistence\Relation\Definition::getInstanceFromArray([
        ['example-1', 'book-count', '\Alvine\Persistence\Relation\Field\Integer']
    ]));
$updateStatement->where(new \Alvine\Persistence\Relation\SQL\Where
    (new \Alvine\Persistence\Relation\Field\Varchar
    ('example-1', 'ISBN')));
$transaction->append(new \Alvine\Persistence\Relation\Query(
    $updateStatement, $records));

/**
 * Ausführen des Queries
 */
try {
    $result=$dataObject->execute($transaction);
    /**
     * Es werden folgende SQL-Anweisungen auf dem Server ausgeführt:
     * START TRANSACTION
     * INSERT INTO `example-1` (`ISBN`,`title`,`record`,`book-count`) 
     *      VALUES ('111-1-86681-001-6','My Title 10','2017-12-31',10)
     * INSERT INTO `example-1` (`ISBN`,`title`,`record`,`book-count`) 
     *      VALUES ('222-2-86681-001-6','My Title 20','2017-12-31',20)
     * UPDATE `example-1` SET `book-count`=11 
     *  WHERE `example-1`.`ISBN`='111-1-86681-001-6'
     * UPDATE `example-1` SET `book-count`=22 
     *  WHERE `example-1`.`ISBN`='222-2-86681-001-6'
     * COMMIT
     */
} catch(\Exception $e) {
    exit-1;
}

if($result->containErrors()) {
    echo "FEHLER\r\n";
    echo (string) $result->getErrors();
    print_r($result);
    exit(1);
}
/**
 * Das Ergebnis des Queries ist eine Collection.
 */
foreach($result AS $resultSet) {
    //print_r($resultSet);
    /** Gibt die Anzahl der betroffenen Datensätze zurückx */
    print_r($resultSet);
}

1a5feac2-d005-438c-c7c7-0bd2c2cfea3b

/**
 * Datenquelle/DataSource erstellen
 */
$dsn=new \Alvine\Persistence\Provider\MySQL\DataSource
    ($host, $port, $database, $table, $user, $password, $parameter);
/**
 * Datenobjekt mit der Verbindung zum Datenbankserver
 */
$dataObject=new \Alvine\Persistence\Relation\SQL\DataObject
    ($dsn, new \Alvine\Types\Map\SimpleMap());


/*
 * Gebündelte Statements
 */
$transaction=new \Alvine\Persistence\Relation\Transaction(true);

/** Erstes Statement */
$records=new \Alvine\Persistence\Relation\Records();

$records->append(new \Alvine\Persistence\Relation\Record(
    ['ISBN'=>'111-1-86681-001-6', 'book-count'=>'10',
    'title'=>'My Title 10', 'record'=>(string) 
        new \Alvine\Date\Date(2017, 12, 31)]));
$records->append(new \Alvine\Persistence\Relation\Record(
    ['ISBN'=>'222-2-86681-001-6', 'book-count'=>'20',
    'title'=>'My Title 20', 'record'=>(string) 
        new \Alvine\Date\Date(2017, 12, 31)]));

$insertStatement=new \Alvine\Persistence\Relation\SQL\Insert\DefinedStatement(
    \Alvine\Persistence\Relation\Definition::getInstanceFromArray([
        ['example-1', 'ISBN'],
        ['example-1', 'title'],
        ['example-1', 'record', 
            '\Alvine\Persistence\Relation\Field\Date'],
        ['example-1', 'book-count', 
            '\Alvine\Persistence\Relation\Field\Integer'],
    ]));
$transaction->append(new \Alvine\Persistence\Relation\Query
    ($insertStatement, $records));

/** Zweites Statement */
$records=new \Alvine\Persistence\Relation\Records();

$records->append(new \Alvine\Persistence\Relation\Record(
    ['ISBN'=>'111-1-86681-001-6', 'book-count'=>'11']));
$records->append(new \Alvine\Persistence\Relation\Record(
    ['ISBN'=>'222-2-86681-001-6', 'book-count'=>'22']));

$updateStatement=new \Alvine\Persistence\Relation\SQL\Update\DefinedStatement(
    \Alvine\Persistence\Relation\Definition::getInstanceFromArray([
        ['example-1', 'book-count', 
            '\Alvine\Persistence\Relation\Field\Integer']
    ]));
$updateStatement->where(new \Alvine\Persistence\Relation\SQL\Where
    (new \Alvine\Persistence\Relation\Field\Varchar
    ('example-1', 'ISBN')));
$transaction->append(new \Alvine\Persistence\Relation\Query
    ($updateStatement, $records));

$statement=new \Alvine\Persistence\Relation\GenericStatement('DO FEHLER');
$transaction->append(new \Alvine\Persistence\Relation\Query($statement));

/**
 * Ausführen des Queries
 */
try {
    $result=$dataObject->execute($transaction);
    /**
     * Es werden folgende SQL-Anweisungen auf dem Server ausgeführt:
     * START TRANSACTION
     * INSERT INTO `example-1` (`ISBN`,`title`,`record`,`book-count`) 
     *        VALUES ('111-1-86681-001-6','My Title 10','2017-12-31',10)
     * INSERT INTO `example-1` (`ISBN`,`title`,`record`,`book-count`) 
     *        VALUES ('222-2-86681-001-6','My Title 20','2017-12-31',20)
     * UPDATE `example-1` SET `book-count`=11 
     *  WHERE `example-1`.`ISBN`='111-1-86681-001-6'
     * UPDATE `example-1` SET `book-count`=22 
     *  WHERE `example-1`.`ISBN`='222-2-86681-001-6'
     * DO FEHLER
     * ROLLBACK
     */
} catch(\Exception $e) {
    exit-1;
}

if($result->containErrors()) {
    echo "FEHLER\r\n";
    echo (string) $result->getErrors();
    print_r($result);
    exit(1);
}
/**
 * Das Ergebnis des Queries ist eine Collection.
 */
foreach($result AS $resultSet) {
    //print_r($resultSet);
    /** Gibt die Anzahl der betroffenen Datensätze zurückx */
    print_r($resultSet);
}

/** EXAMPLE:END * */
echo "\n".$profiler->record('end')->getDuration();

Rollback

Verlorene" Auto-Inkrement-Werte und Sequenzlücken

Wenn in allen Sperrmodi (0, 1 und 2) eine Transaktion, die Auto-Inkrement-Werte erzeugt hat, zurückgesetzt wird, sind diese Auto-Inkrement-Werte "verloren". Sobald ein Wert für eine Spalte mit automatischer Erhöhung erzeugt wurde, kann er nicht mehr zurückgesetzt werden, unabhängig davon, ob die Anweisung "INSERT-like" abgeschlossen ist oder nicht und ob die enthaltene Transaktion zurückgesetzt wird oder nicht. Solche verlorenen Werte werden nicht wiederverwendet. Daher kann es zu Lücken in den Werten kommen, die in einer AUTO_INCREMENT-Spalte einer Tabelle gespeichert sind.

Quelle dev.mysql.com