Sunteți pe pagina 1din 6

Codeigniter, Transacciones

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.

Despus de una serie de procesos, verificamos si hubo algn error:

if ($this->db->trans_status() ===
FALSE)

Si la transaccin fall por algn motivo, volvemos todo atrs con rollback:

$this->db->trans_rollback();

Si no hubo errores y todo sali bien, entonces podemos hacer un commit:

$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.

Vamos a crear tres tablas con el siguiente cdigo:

Una tabla para guardar los servicios:

CREATE TABLE servicios(


servicio_id tinyint(2) primary key not
null,
nombre varchar(100) not null
)ENGINE=innoDB;

Otra para los clientes:

CREATE TABLE clientes(


cliente_id int(10) unsigned not null auto_increment primary
key,
nombre varchar(100) not null,
apellido varchar(100) not null,
domicilio varchar(100) not null,
telefono varchar(100) not null,
email varchar(100) unique not null,
fecha_registro datetime not null
)ENGINE=innoDB;

Y finalmente la relacin entra ambas:

CREATE TABLE servicios_clientes(


servicio_id tinyint(2) not null,
cliente_id int(10) unsigned not
null,
primary key(servicio_id,
cliente_id),
foreign key(servicio_id)
references servicios(servicio_id),
foreign key(cliente_id)
references clientes(cliente_id)
)ENGINE=innoDB;

Adems vamos a insertar cules son los servicios disponibles con su respectivo cdigo:

INSERT INTO servicios(servicio_id,


nombre)
VALUES(11, 'Banda ancha');
INSERT INTO servicios(servicio_id,
nombre)
VALUES(22, 'Televisin por cable');
INSERT INTO servicios(servicio_id,
nombre)
VALUES(33, 'Telfono');

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:

email varchar(100) unique not


null,

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.

Caso 2: Columna nica

$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.

Caso 3: Datos duplicados

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.

Caso 4: Clave fornea de un registro que no existe

$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

S-ar putea să vă placă și