Connexions, CRUD i Transaccions
Unitat 05 - DWES
L'accés a bases de dades és la base de quasi tots els sistemes de gestió actuals
Sistemes per interconnectar codi amb BD:
En aquest tema usarem MySQLi
États possibles:
Exemple: Transferència bancària (resta + suma)
// Paràmetres de connexió
$servidor = "localhost";
$usuari = "root";
$contrasenya = "";
$bd = "bdprova";
// Realització de la connexió
$con = mysqli_connect($servidor, $usuari, $contrasenya, $bd);
// Comprovar connexió
if (!$con) {
die("Error: " . mysqli_connect_error());
}
echo "Connectat correctament!";
Per evitar problemes amb accents, dièresis, etc:
// Establir charset (UTF-8)
mysqli_set_charset($con, "utf8mb4");
// O dins la connexió
$con = mysqli_connect(
$servidor, $usuari, $contrasenya, $bd
);
mysqli_set_charset($con, "utf8mb4");
Create • Read • Update • Delete
// Instrucció SQL INSERT
$sql = "INSERT INTO estudiant
VALUES ('52666666F', 'Toni Blanco', 23, '2GM')";
// Executar
$res = mysqli_query($con, $sql);
// Comprovar
if (mysqli_errno($con) != 0) {
die("Error inserció: " . mysqli_error($con));
}
echo "Dada inserida correctament!";
echo "ID: " . mysqli_insert_id($con);
// SELECT simple
$sql = "SELECT nom, edat FROM estudiant
WHERE dni = '52222222B'";
$res = mysqli_query($con, $sql);
if (mysqli_errno($con) != 0) {
die("Error consulta: " . mysqli_error($con));
}
// Obtenir fila
$fila = mysqli_fetch_assoc($res);
if ($fila) {
echo "Nom: " . $fila['nom'];
echo "Edat: " . $fila['edat'];
} else {
echo "No trobat";
}
$sql = "SELECT nom, edat FROM estudiant";
$res = mysqli_query($con, $sql);
// Recórrer resultats amb cursor
while ($fila = mysqli_fetch_assoc($res)) {
$nom = $fila['nom'];
$edat = $fila['edat'];
echo "Nom: $nom | Edat: $edat <br>";
}
// Alliberar resultats
mysqli_free_result($res);
// Instrucció UPDATE
$sql = "UPDATE estudiant
SET edat = 25
WHERE dni = '52666666F'";
$res = mysqli_query($con, $sql);
// Comprovar
if (mysqli_errno($con) != 0) {
die("Error modificació: " . mysqli_error($con));
}
// Mostrar files afectades
$files_afectades = mysqli_affected_rows($con);
echo "Files modificades: " . $files_afectades;
// Instrucció DELETE
$sql = "DELETE FROM estudiant
WHERE dni = '52666666F'";
$res = mysqli_query($con, $sql);
// Comprovar
if (mysqli_errno($con) != 0) {
die("Error eliminació: " . mysqli_error($con));
}
// Mostrar files eliminades
$files_eliminades = mysqli_affected_rows($con);
echo "Files eliminades: " . $files_eliminades;
Bon:
DELETE FROM estudiant WHERE dni = '52666666F';
Dolent (PERILLÓS!):
DELETE FROM estudiant; // Elimina TOTS!
$sql = "SELECT dni, nom, edat FROM estudiant";
$res = mysqli_query($con, $sql);
// Accés per nom de camp
$fila = mysqli_fetch_assoc($res);
echo $fila['nom']; // Array associatiu
echo $fila['edat'];
Avantatge: Codi més llegible
$sql = "SELECT dni, nom, edat FROM estudiant";
$res = mysqli_query($con, $sql);
// Accés per posició
$fila = mysqli_fetch_row($res);
echo $fila[0]; // dni
echo $fila[1]; // nom
echo $fila[2]; // edat
Avantatge: Lleugerament més ràpid
// Patterns comuns
$sql = "SELECT * FROM estudiant";
$res = mysqli_query($con, $sql);
// Pattern 1: While amb fetch_assoc
while ($fila = mysqli_fetch_assoc($res)) {
echo $fila['nom'] . "<br>";
}
// Pattern 2: Contar resultats
$num_resultats = mysqli_num_rows($res);
echo "Total: $num_resultats";
// Alliberar memoria
mysqli_free_result($res);
// Iniciar transacció
mysqli_query($con, "BEGIN");
try {
// Operació 1
mysqli_query($con, "UPDATE cuentas SET saldo = saldo - 1000
WHERE id = 1");
// Operació 2
mysqli_query($con, "UPDATE cuentas SET saldo = saldo + 1000
WHERE id = 2");
// Si tot va bé: COMMIT
mysqli_query($con, "COMMIT");
echo "Transferència realizada!";
} catch (Exception $e) {
// Si error: ROLLBACK
mysqli_query($con, "ROLLBACK");
echo "Error: " . $e->getMessage();
}
// Simular eliminació amb rollback
mysqli_query($con, "BEGIN");
$sql = "DELETE FROM estudiant WHERE dni = '52666666F'";
mysqli_query($con, $sql);
// Verificar eliminació
$sql2 = "SELECT COUNT(*) as quants FROM estudiant
WHERE dni = '52666666F'";
$res = mysqli_query($con, $sql2);
$fila = mysqli_fetch_assoc($res);
echo "Després eliminar: " . $fila['quants']; // 0
// Desfer els canvis
mysqli_query($con, "ROLLBACK");
// Verificar recuperació
$sql3 = "SELECT COUNT(*) as quants FROM estudiant
WHERE dni = '52666666F'";
$res = mysqli_query($con, $sql3);
$fila = mysqli_fetch_assoc($res);
echo "Després rollback: " . $fila['quants']; // 1
Operacions:
-- Taula CURS
CREATE TABLE CURS (
nom VARCHAR(20) PRIMARY KEY,
hores INT
);
-- Taula ESTUDIANT amb clau forana
CREATE TABLE ESTUDIANT (
dni VARCHAR(9) PRIMARY KEY,
nom VARCHAR(50),
curs VARCHAR(20),
FOREIGN KEY (curs) REFERENCES CURS(nom)
);
Quando s'elimina una fila referenciada:
-- Exemple CASCADE
ALTER TABLE ESTUDIANT
ADD FOREIGN KEY (curs) REFERENCES CURS(nom)
ON DELETE CASCADE
ON UPDATE CASCADE;
// Validar clau forana ANTES de INSERT
$curs_voler = "1GInf";
$sql_check = "SELECT COUNT(*) as num
FROM CURS WHERE nom = '$curs_voler'";
$res = mysqli_query($con, $sql_check);
$fila = mysqli_fetch_assoc($res);
if ($fila['num'] > 0) {
// Curs existeix - es pot insertar
$sql_insert = "INSERT INTO ESTUDIANT
VALUES ('52222222B', 'Joan', '1GInf')";
mysqli_query($con, $sql_insert);
} else {
echo "Error: Curs no existeix!";
}
// Obtenir número d'error (0 = sense error)
$error_num = mysqli_errno($con);
// Obtenir descripció d'error
$error_msg = mysqli_error($con);
// Comprovar si hi ha error
if (mysqli_errno($con) != 0) {
echo "Error: " . mysqli_error($con);
die();
}
// Exemple complet
$sql = "SELECT * FROM estudiant WHERE dni = '52222222B'";
$res = mysqli_query($con, $sql);
if (!$res) {
printf("Error: %s\n", mysqli_error($con));
exit();
}
// Nombre de files afectades (UPDATE, DELETE, INSERT)
$files_afectadas = mysqli_affected_rows($con);
// Nombre de files en resultat SELECT
$num_resultats = mysqli_num_rows($res);
// Nombre de camps en resultat
$num_camps = mysqli_num_fields($res);
// ID de l'últim INSERT (si autoincrement)
$ultimo_id = mysqli_insert_id($con);
// Exemples
$sql = "UPDATE estudiant SET edat = 25 WHERE edat < 20";
mysqli_query($con, $sql);
echo "Actualitzats: " . mysqli_affected_rows($con);
// EVITAR (vulnerable a injection)
$dni = $_GET['dni'];
$sql = "SELECT * FROM estudiant WHERE dni = '$dni'";
// USAR (segur)
$dni = $_GET['dni'];
$sql = "SELECT * FROM estudiant WHERE dni = ?";
$stmt = mysqli_prepare($con, $sql);
mysqli_stmt_bind_param($stmt, "s", $dni);
mysqli_stmt_execute($stmt);
$res = mysqli_stmt_get_result($stmt);
$fila = mysqli_fetch_assoc($res);
// ✓ Checklist recomana
✓ Verificar conexió
✓ Establir charset (utf8mb4)
✓ Usar prepared statements
✓ Comprovar errors (mysqli_errno)
✓ Alliberar resultats (mysqli_free_result)
✓ Desconnectar (mysqli_close)
✓ Mantenir secrets seguros (.env)
✓ No fer queries N+1
✓ Loguear errors per debugging
✓ Testejar amb dades reals
CRUD d'Estudiants amb Totes les Bones Pràctiques
proyecto/
├── config/
│ └── db.php ← Connexió
├── crud/
│ ├── create.php
│ ├── read.php
│ ├── update.php
│ └── delete.php
├── index.php
└── estudiantes.sql ← Dump BD
<?php
// Paràmetres de connexió
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'academica');
// Connexió
$con = mysqli_connect(
DB_HOST, DB_USER, DB_PASS, DB_NAME
);
// Verificar
if (!$con) {
die("Error: " . mysqli_connect_error());
}
// Charset
mysqli_set_charset($con, "utf8mb4");
?>
<?php
require '../config/db.php';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$dni = $_POST['dni'] ?? '';
$nom = $_POST['nom'] ?? '';
$edat = $_POST['edat'] ?? '';
$curs = $_POST['curs'] ?? '';
// Validar
if (empty($dni) || empty($nom)) {
echo "Error: Camps obligatoris";
exit;
}
// Prepared statement
$sql = "INSERT INTO estudiant (dni, nom, edat, curs)
VALUES (?, ?, ?, ?)";
$stmt = mysqli_prepare($con, $sql);
mysqli_stmt_bind_param($stmt, "ssis", $dni, $nom, $edat, $curs);
if (mysqli_stmt_execute($stmt)) {
echo "Estudiant creat!";
} else {
echo "Error: " . mysqli_error($con);
}
mysqli_stmt_close($stmt);
}
?>
<?php
require '../config/db.php';
// Obtenir tots els estudiants
$sql = "SELECT * FROM estudiant ORDER BY nom";
$res = mysqli_query($con, $sql);
if (!$res) {
die("Error: " . mysqli_error($con));
}
echo "<table border='1'>";
echo "<tr><th>DNI</th><th>Nom</th><th>Edat</th><th>Curs</th></tr>";
while ($fila = mysqli_fetch_assoc($res)) {
echo "<tr>";
echo "<td>" . $fila['dni'] . "</td>";
echo "<td>" . $fila['nom'] . "</td>";
echo "<td>" . $fila['edat'] . "</td>";
echo "<td>" . $fila['curs'] . "</td>";
echo "</tr>";
}
echo "</table>";
mysqli_free_result($res);
mysqli_close($con);
?>
Accés a Bases de Dades amb PHP i MySQL
Presentació creada amb Reveal.js