RSS (Really Simple Syndication) - novinky na webových stránkách

Transakce v PHP s mysqli a MariaDB

Pokud ve spolupráci s databází MariaDB (svobodný nástupce MySQL) využíváte programovací jazyk 
PHP verze => 8.4 (rok 2025) a k MariaDB přistupujete přes objektové rozhraní mysqli, můžete využívat speciálních objektových metod tohoto rozhraní, které práci s transakcemi zastřešují. Navíc je žádoucí v transakcích používat parametrizované dotazy.

Základem objektového přístupu k rozhraní mysqli a transakcím v PHP jsou tyto klíčové prvky:

  1. $mysqli = new mysqli("localhost", "testik", "testik", "testik");   // přihlášení uživatele k databázi
    //============ zde transakce začíná ==============
  2. $mysqli->begin_transaction();  // začátek transakce
  3. Provedení potřebných databázových operaccí uvnitř bloku try-catch, například:
    ✅ odečtení častky z účtu odesílatele, 
    ✅ přičtení částky na účet příjemce,
    ✅ zapsání do tabulky provedených transakcí

  4. $mysqli->commit();    // pokud předcházející SQL dotazy proběhly bezchybně, potvrdit transakci

    nebo

    $mysqli->rollback();   // zrušit transakci (storno transakce, vrácení zpět) při chybě
    //============ zde transakce končí ===============
  5. $mysqli->close();   // ukončení spojení k MariaDB

Viz transakce v PHP s mysqli rozhraním.

Transakce jsou důležitým nástrojem pro zajištění konzistence dat v databázi. Umožňují seskupit více databázových operací do jednoho celku, který se buď celý provede, nebo se neprovedou žádné z jeho částí. 
Chcete-li používat transakce, musíte používat tabulky typu InnoDB. Jde o zachování integrity databáze. Zjednodušeně se to přirovnává k převodům peněz u bankovních účtů. Pokud odešleme nějakou čásku na bankovní účet příjemce, nejdříve se nám odečte částka z účtu a poté se přičte na účet příjemce.
Ale co když po odečtení částky z našeho účtu se něco pokazí a částka se na účet příjemce nepřipíše? V takovém případě by odeslaná částka byla ztracena, zmizela. Je jasné, že takový případ nesmí nikdy nastat, v takovém případě je nutno používat transakce.

ACID

Transakce by měly splňovat takzvaná ACID pravidla. Tato zkratka je složena z počátečních písmen 4 vlastností správné transakce (angl. atomicity - A, consistency - C, isolation - I, durability - D):

Všechna pravidla ACID splňuje v PHP objektové mysqli rozhraní nad databází MariaDB (používá i google).

Příklad implementace transakce v PHP objektově s mysqli

Pro praktické vyzkoušení transakcí je třeba si v PHPMyadmin vytvořit databázi "testik", uživatele "testik" s heslem "testik", tabulky "ucty" a "prevody". V tabulce převody budou uložené všechny uskutečněné transakce. Samozřejmě to vytváříme na lokálním notebooku (PC), ne na serveru.

SQL pro vytvoření tabulky v konzoli nebo například v MyPHPadmin:

START TRANSACTION;
CREATE TABLE `prevody` (
`prevod_id` int(10) UNSIGNED NOT NULL,
`cas` timestamp NOT NULL DEFAULT current_timestamp(),
`z_uctu_id` int(10) UNSIGNED DEFAULT NULL,
`na_ucet_id` int(10) UNSIGNED DEFAULT NULL,
`castka` decimal(19,2) UNSIGNED DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_czech_ci;
CREATE TABLE `ucty` (
`ucet_id` int(10) UNSIGNED NOT NULL,
`klient` varchar(50) DEFAULT NULL,
`aktualni_zustatek` decimal(19,2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_czech_ci;
INSERT INTO `ucty` (`ucet_id`, `klient`, `aktualni_zustatek`) VALUES
(1, 'Petr Novák', 10000),
(2, 'Josef Lux', 10000),
(3, 'Anna Bílá', 10000);
ALTER TABLE `prevody`
ADD PRIMARY KEY (`prevod_id`);
ALTER TABLE `ucty`
ADD PRIMARY KEY (`ucet_id`);
ALTER TABLE `prevody`
MODIFY `prevod_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `ucty`
MODIFY `ucet_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
COMMIT;

Pokud máte tabulky úspěšně vytvořeny, je možno začat psát kód v PHP. Nejdříve si vytvoříme soubor "config.ini.php":

<?php
define ("DB_HOST", "localhost");
define ("DATABAZE", "testik");
define ("DB_USER", "testik");
define ("PASVORTO", "testik");
?>

Ještě styl "mysql.css" pro zobrazení tabulek:

.tb_vypis {
font-size: smaller;
border-collapse: collapse;
height:auto;
margin: 2px;
}
.tb_vypis th {
background-color: #000000;
color: #FFFFFF;
text-align: center !important;
border: 1px solid #AAAAAA;
}
.tb_vypis td {
border: 1px solid #AAAAAA;
}
.tb_vypis a {
text-decoration: none;
}
.vypis_vpravo {
text-align: right !important;
}

A nyní je již možno si vytvořit soubor "index.php":

<?php
require_once("config.ini.php");          // Načtení konfigurace MariaDB
echo '<!DOCTYPE html>';
echo '<html lang="cs">';
echo '<head>';
echo '<meta charset="utf-8" />';
echo '<meta name="viewport" content="width=device-width, initial-scale=1.0" />';
echo '<meta name="robots" content="all" />';
echo '<meta name="keywords" content="Ukázka transakcí" />';
echo '<meta name="description" content="Ukázka transakcí" />';
echo '<meta name="autor" content="Kocour" />';
echo '<title>Ukázka transakcí</title>';
echo '<link href="mysql.css" rel="stylesheet" type="text/css" />';
echo '</head>';
echo '<body>';
echo '<h1>Ukázka transakcí</h1>'; 
// Zobrazení formuláře
echo '<form action="" method="post">';
echo '<fieldset>';
echo '<legend>Zadání částky k převodu</legend>';
echo '<table>';
echo '<tr>';
echo '<td>Zadej účet odesílatele</td><td><input type="text" name="odesilatel" value="" size="" /></td>';
echo '</tr>';
echo '<tr>';
echo '<td>Zadej účet příjemce</td><td><input type="text" name="prijemce" value="" size="" /></td>';
echo '</tr>';
echo '<tr>';
echo '<td>Zadej částku v Kč</td><td><input type="text" name="castka" value="" size="" /></td>';
echo '</tr>';
echo '</table>';
echo '<br /><input type="submit" name="poslat" value="Pošli" />';
echo '</fieldset>';
echo '</form>';
try {
$mysqli = new mysqli(DB_HOST, DB_USER, PASVORTO, DATABAZE);    // přihlášení uživatele k databázi
if ($mysqli->character_set_name()!="utf8mb4") { $mysqli->set_charset("utf8mb4"); }
} catch (Exception $e) {
exit("Do databáze se nelze připojit!<br />".$e->getMessage());
}
// zpracování odeslaných dat z formuláře 
if (!empty($_POST['poslat']) and !empty($_POST['odesilatel']) and !empty($_POST['prijemce']) and !empty($_POST['castka'])) {    
$ucet_odesilatele = $_POST['odesilatel'];
$ucet_prijemce = $_POST['prijemce'];
$castka = $_POST['castka']; 
// konverze českého čísla na number mariaDB standard
$zdroj = array(" ",","); $cil   = array("","."); $castka = str_replace($zdroj, $cil, $castka);
// ====================== začátek transakce ====================
$mysqli->begin_transaction();                                             
try {
// odečtení častky z účtu odesílatele, parametrizovaný dotaz
$ucet_id = $ucet_odesilatele;
$parametry = array($castka,$ucet_id);
$stmt = $mysqli->prepare("UPDATE ucty SET aktualni_zustatek = aktualni_zustatek - ? WHERE ucet_id = ?");     
$stmt->bind_param('di', ...$parametry);
$stmt->execute();
$stmt->close();

// přičtení částky na účet příjemce    
$ucet_id = $ucet_prijemce;
$parametry = array($castka,$ucet_id);
$stmt = $mysqli->prepare("UPDATE ucty3 SET aktualni_zustatek = aktualni_zustatek + ? WHERE ucet_id = ?");
$stmt->bind_param('di', ...$parametry);
$stmt->execute();
$stmt->close();

/*
// zapsání do tabulky provedených transakcí
$parametry = array($ucet_odesilatele,$ucet_prijemce,$castka);
$stmt = $mysqli->prepare("INSERT INTO prevody (z_uctu_id, na_ucet_id, castka) values (?, ?, ?)");
$stmt->bind_param('iid', ...$parametry);
$stmt->execute();
$stmt->close();
*/

// zapsání do tabulky provedených transakcí, tento zkrácený zápis parametrizovaného dotazu je možno použít od PHP 8.2
$parametry = array($ucet_odesilatele,$ucet_prijemce,$castka);
$mysqli->execute_query("INSERT INTO prevody (z_uctu_id, na_ucet_id, castka) values (?, ?, ?)", $parametry);


$mysqli->commit();                          // potvrdit transakci
} catch (Exception $e) {
$mysqli->rollback();                       // zrušit transakci
echo "Něco se pokazilo, transakce byla zrušena! ".$e->getMessage()."<br>".$e->getTraceAsString()."<br>";
}  
// ================ ukončení transakce ====================

}                     // KONEC zpracování odeslaných dat z formuláře                                 
echo "<br>zobrazení zůstatků na účtech";
$vysledek = $mysqli->query("select * from ucty"); 
echo "<table class=\"tb_vypis\">\n";
echo "<tr><th>ucet_id</th><th>klient</th><th>aktualni_zustatek Kč</th></tr>";  // hlavička
while ($zaznam = $vysledek->fetch_assoc()) {
echo "<tr><td class=\"vypis_vpravo\">".$zaznam['ucet_id']."</td><td>".$zaznam['klient']."</td><td class=\"vypis_vpravo\">".number_format($zaznam['aktualni_zustatek'],2,',',' ')."</td></tr>";
}
echo "</table>\n";

echo "<br>výpis převodů, transakcí";
$vysledek = $mysqli->query("select date_format(cas,'%d.%m.%Y %H:%i:%s') as 'čas',z_uctu_id as 'z účtu',klient,na_ucet_id as 'na účet',CONCAT(FORMAT(castka, 2, 'cs_CZ'),' Kč') as 'částka' from prevody join ucty on prevody.z_uctu_id=ucty.ucet_id order by prevod_id desc limit 20");
echo "<table class=\"tb_vypis\">\n";
echo "<tr><th>čas</th><th>z účtu</th><th>klient</th><th>".htmlspecialchars('->')."</th><th>na účet</th><th>částka</th></tr>";  // hlavička
while ($zaznam = $vysledek->fetch_assoc()) {
echo "<tr><td>".$zaznam['čas']."</td><td class=\"vypis_vpravo\">".$zaznam['z účtu']."</td><td>".$zaznam['klient']."</td><td>".htmlspecialchars('->')."</td><td class=\"vypis_vpravo\">".$zaznam['na účet']."</td><td class=\"vypis_vpravo\">".$zaznam['částka']."</td></tr>";
}
echo "</table>\n";

$mysqli->close();   // ukončení spojení k MariaDB 
echo "</body>\n";
echo '</html>';
?>

Klíčové kroky u transakcí

  1. Zahájíte transakci voláním $mysqli->begin_transaction().
  2. Provedete potřebné databázové operace uvnitř bloku try-catch.
  3. Pokud vše proběhne v pořádku, uložíte změny voláním $mysqli->commit().
  4. V případě chyby vrátíte databázi do předchozího stavu voláním $mysqli->rollback().

Tento přístup zajistí, že se buď všechny operace provedou, nebo se neprovedou žádné.

U výše uvedeného výpisu php kódu je třeba si všimnout u přihlašování k databázi ošetření chyb pomocí vyjímek. Často se stává, že vývojáři sice tvoří kód v objektovém stylu, ale zapomínají na ošetření chyb pomocí vyjímek. Místo toho používají zastaralý způsob ošetření chyb v objektovém programování pomocí návratové hodnoty funkce, což je špatně!
Pro názornost takového špatného kódu si uvedeme příklad:

$conn = new mysqli(DB_HOST, DB_USER, PASVORTO, DATABAZE);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}

Správné ošetření chybného přihlášení k databázi pomocí vyjímky

try {
$mysqli = new mysqli(DB_HOST, DB_USER, PASVORTO, DATABAZE);    // přihlášení uživatele k databázi
if ($mysqli->character_set_name()!="utf8mb4") { $mysqli->set_charset("utf8mb4"); }  // zjištění / změna kódování
} catch (Exception $e) {
exit("Do databáze se nelze připojit!<br />".$e->getMessage()); // při chybě ukončení s výpisem chybové hlášky
}
storno transakce

ošetřená vyjímka

Na řádku 57 v souboru "index.php" je úmyslná chyba (místo '...ucty3...' má být '...ucty...'). Tímto se při zadání účtů a částky ve formuláři vyvolá vyjímka a její ošetření. Transakce je tím zrušena - stornována.

Objektové zpracování chybného přihlášení, ošetření zadávání a zobrazování českého formátu čísel (částek, zůstatků a měny), české zobrazování datumů, zpracování vyjímek

  1. MySQLi objektově v PHP (ošetření PHP vyjímek v objektovém programování)
    Objektové zpracování přihlášení do databáze pomocí ošetření PHP vyjímek, ošetření transakcí pomocí vyjímek (commit = potvrzení transakce, rollback = zrušení transakce).
    try { ... } catch (Exception $e) {  $mysqli->rollback(); ".$e->getMessage()."<br>"; }
  2. Návod na zkrácený zápis parametrizovaného dotazu s execute_query
    Je možno používat execute_query() od PHP 8.2 a vyšší.
  3. zadávání českého formátu čísel, částek
    // konverze českého čísla na number mariaDB standard
    PHP:
    $zdroj = array(" ",","); $cil = array("",".");
    $castka = str_replace($zdroj, $cil, $castka);

  4. zobrazování českého formátu čísel, částek
    PHP: number_format($zaznam['aktualni_zustatek'],2,',',' ')
    SQL: CONCAT(FORMAT(castka, 2, 'cs_CZ'),' Kč') as 'částka'
  5. české zobrazování datumů
    SQL: select date_format(cas,'%d.%m.%Y %H:%i:%s') as 'čas'

transakce v PHP s mysqli rozhraním

Upozornění

Interní funkce PHP používají hlavně hlášení chyb, výjimky používají pouze moderní objektově orientovaná rozšíření.
Chyby však lze snadno převést na výjimky pomocí ErrorException.
Tato technika však funguje pouze s nefatálními chybami.

Error exception

function exceptions_error_handler($severity, $message, $filename, $lineno) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
set_error_handler('exceptions_error_handler');

Odkazy

  1. Jak správně provádět transakce

Komentáře

1. Přezdívka: Kastoro, email: , 28.09.2025 20:27:17
Je jen třeba připomenout, jak v Linuxu nainstalovat LAMP (Linux, Apache2, MariaDB, PHP):

$ sudo apt update
$ sudo apt install apache2 php libapache2-mod-php php-mysql mariadb-server

Kdokoliv může přidávat komentáře ke článkům bez registrace. Zadá si libovolnou přezdívku a napíše komentář.

Jak používat messenger Signál


SSL pro weby od 11/2015 zdarma


MS WINDOWS 10, 11 - sběr informací o uživateli


DEBIAN 13 (trixie) - OS zdarma debian vyšel 9.8..2025

debian
debian edu - debian pro školy a školní prostředí


Zranitelnost „ROM-0“ routerů


Předali data tajným službám
Americké bezpečnostní agentuře (NSA) předali data Microsoft, Yahoo, Google, Facebook...


Itálie preferuje open source
Italský parlament schválil zákon, který nařizuje státním institucím pořizovat otevřený software před komerčním. To znamená LINUX místo MS-WINDOWS, LIBRE OFFICE místo MS OFFICE atd.

14.12. 2025 11:29:45
  • Redakční systém MRS
  • 10 nečastějších zranitelností WEBU
  • Esperantoesperanto - univerzální mezinárodní jazyk
  • Kryptografie okolo nás - kniha popisuje využití kryptografie v běžném životě
  • SMS zdarma - posílání SMS zdarma
  • proč LINUX
  • základy LINUXU
  • Přepsání disku náhodnými daty
  • Software na úřadech - jeho otevřené alternativy
  • Řekněte sbohem Microsoftu
  • Rychlost připojení - změřte si svoji rychlost
  • SEO servis
  • Jak psát web
  • Zákony - občanský, autorský, obchodní zákoník atd.
  • Infosoud - nalezení stání a průběhu jednání
  • Soudní rozhodnutí - nalezení rozsudků
  • ARES - registr ekonomických subjektů
  • Katastr nemovitostí
  • Broďan - brodské nezávislé zpravodajství
  • Smajlíky - v UTF-8 Smajlíky
26.11. 2025 10:20:23
Návštěvy
Celkem: 354175
Týden: 521
Dnes: 47
  přihlásit poslední změna: 31.12. 2025 16:03:44