Documente Academic
Documente Profesional
Documente Cultură
fernando-gaitan.com.ar /codeigniter-transacciones/
Ferchu 16 junio,
2017
Para el que nunca lo haya visto, un transaccin en base de datos es una serie de
operaciones que se ejecutan como si fuesen una sola, y si una de estas falla, todos los
cambios realizados hasta ese punto volvern atrs. Esto se aplica para aquellas
operaciones en base de datos que realizan cambios en las tablas; un INSERT, un
UPDATE o un DELETE; a diferencia de los SELECT que no realizan alteraciones en las
filas.
Supongamos esta situacin: hay una operacin bancaria en donde una persona va a
hacer una transferencia de dinero de su cuenta a otra. Esto llevara una serie de pasos,
se me ocurre: restar el dinero en la cuenta emisora, generar el registro de dicha
transferencia y por ltimo sumar el monto a la cuenta receptora. Pero por alguna razn uno de estas operaciones
no funciona correctamente. Por ejemplo la cuenta receptora no puede recibir transferencias, entonces todo volvera
atrs y el dinero que iba a transferir el emisor obviamente no se resta.
Se dice que las transacciones son el todo o nada, porque o se ejecutan todos los procesos de forma correcta o
todos se cancelan.
Ahora, llevando esto a la prctica, en Codeigniter, una transaccin puede realizarse de modo muy sencillo.
Utilizando el objeto db, el cual como sabemos trabaja con todo lo relacionado a la base de datos.
Iniciamos la transaccin:
$this->db->trans_begin();
Todo lo que se haga a partir de aqu puede guardarse o cancelarse por completo.
if ($this->db->trans_status() ===
FALSE)
Si la transaccin fall por algn motivo, volvemos todo atrs con rollback:
$this->db->trans_rollback();
$this->db->trans_commit();
Ejemplo
Supongamos que tenemos una base de datos en donde los clientes se registran e indican cules son los servicios
1/6
que desean adquirir.
Adems vamos a insertar cules son los servicios disponibles con su respectivo cdigo:
2/6
Ahora bien, debemos detenernos en ciertos puntos. En primer lugar una restriccin de la base de datos es que el
email del usuario debe ser nico:
Por tanto, si otro usuario intenta registrarse con una direccin de correo electrnico ya existente, debera devolver
un error.
Adems los nicos servicios que hay tienen los siguientes cdigo: 11, 22, 33. Al intentar insertar una relacin
servicios-clientes con otro id, tambin sera incorrecto.
Y por ltimo, en la tabla que relaciona a los servicios y los clientes, cada registro tendr como clave primaria el id
del cliente y el id del servicio, como un identificador mltiple:
primary key(servicio_id,
cliente_id)
Por tanto, slo podr haber una nica combinacin. Si se intenta insertar un segundo registro con un id y un
servicio, en donde ambos se relacionan en otra fila, tambin debera dar un error.
Para representar a la entidad clientes vamos a crear un modelo llamado Cliente_model.php, con el siguiente
cdigo:
3/6
<?php
class Cliente_model extends CI_Model {
public function __construct()
{
parent::__construct();
}
public function registrar($data)
{
//Iniciamos la transaccin.
$this->db->trans_begin();
//Intenta insertar un cliente.
$this->db->insert('clientes', array(
'nombre' => $data['nombre'],
'apellido' => $data['apellido'],
'domicilio' => $data['domicilio'],
'telefono' => $data['telefono'],
'email' => $data['email'],
'fecha_registro' => date('Y-m-d H:i:s')
));
//Recuperamos el id del cliente registrado.
$cliente_id = $this->db->insert_id();
//Insertamos los servicios que desea adquirir el cliente.
foreach($data['servicios'] as $servicio_id){
$this->db->insert('servicios_clientes', array(
'servicio_id' => $servicio_id,
'cliente_id' => $cliente_id
));
}
if ($this->db->trans_status() === FALSE){
//Hubo errores en la consulta, entonces se cancela la
transaccin.
$this->db->trans_rollback();
return false;
}else{
//Todas las consultas se hicieron correctamente.
$this->db->trans_commit();
return true;
}
}
}
Simplemente lo que hace el mtodo es insertar un cliente, y luego los servicios que desea adquirir ste.
Ahora, vamos a crear un controlador cualquier para incluir nuestro modelo y probar de forma rpida el
funcionamiento de este mtodo con transacciones.
Caso 1: Ok
4/6
$this->load->model('cliente_model');
$resultado = $this->cliente_model->registrar(array(
'nombre' => 'Juan',
'apellido' => 'Prez',
'domicilio' => 'Calle Falsa 1234',
'telefono' => '55555555',
'email' => 'juan_perez@mail.com',
'servicios' => array(11, 22)
));
if($resultado){
echo 'El cliente fue registrado correctamente';
}else{
echo 'El cliente NO fue registrado, porque hubo errores';
}
El cliente se inserta, pero tambin lo hacen los servicios. No hubo ningn error, por eso se puede hacer commit.
$this->load->model('cliente_model');
$resultado = $this->cliente_model->registrar(array(
'nombre' => 'Cosme',
'apellido' => 'Fulanito',
'domicilio' => 'Calle sin nmero',
'telefono' => '55555555',
'email' => 'juan_perez@mail.com',
'servicios' => array(11, 22)
));
if($resultado){
echo 'El cliente fue registrado correctamente';
}else{
echo 'El cliente NO fue registrado, porque hubo
errores';
}
Se intenta insertar un cliente con un correo que ya le pertenece a otro, se produce el primer error. Los cambios se
vuelven para atrs con rollback. No se inserta el cliente y tampoco los servicios.
5/6
$this->load->model('cliente_model');
$resultado = $this->cliente_model->registrar(array(
'nombre' => 'Cosme',
'apellido' => 'Fulanito',
'domicilio' => 'Calle sin nmero',
'telefono' => '55555555',
'email' => 'cosme_fulanito@mail.com',
'servicios' => array(11, 22, 33, 22)
));
if($resultado){
echo 'El cliente fue registrado correctamente';
}else{
echo 'El cliente NO fue registrado, porque hubo errores';
}
Se intenta insertar con un cliente dos veces el mismo servicio, lo cual nuestra base de datos no nos permite. Esto
no slo hace que no se inserten los servicios, sino que se cancela el paso previo de registrar al cliente, a pesar de
que los datos eran correctos.
$this->load->model('cliente_model');
$resultado = $this->cliente_model->registrar(array(
'nombre' => 'Cosme',
'apellido' => 'Fulanito',
'domicilio' => 'Calle sin nmero',
'telefono' => '55555555',
'email' => 'cosme_fulanito@mail.com',
'servicios' => array(55)
));
if($resultado){
echo 'El cliente fue registrado correctamente';
}else{
echo 'El cliente NO fue registrado, porque hubo errores';
}
En este ltimo caso, al igual que el anterior, no hay errores en los datos del cliente, pero se est intentando insertar
un en la tabla servicios_clientes una clave externa de un registro que no existe en la tabla servicios. La transaccin
devuelve errores, y el paso anterior se elimina tambin.
Nota: Si ests en modo development, seguro te va a mostrar los errores de SQL por pantalla. Al cambiarlo a modo
production, no te mostrar los errores, y el mtodo registrar() te devolver false, debido al fallo.
6/6