web-dev-qa-db-fra.com

Transactions Codeigniter

J'utilise des transactions Codeigniter

$this->db->trans_start();
$this->db->query('AN SQL QUERY...');
$this->db->trans_complete();

Cela fonctionne bien, le problème que j'ai est qu'à l'intérieur du trans_start et trans_complete J'appelle d'autres fonctions et ces fonctions traitent de la base de données afin qu'elles contiennent des insertions et des mises à jour et quelques suppressions ... ex:

$this->db->trans_start();
 $this->utils->insert_function($data);
 $this->utils->update_function2($test);
$this->db->trans_complete();

Maintenant, si ces fonctions sont exécutées et que certaines erreurs se produisent, CodeIgniter ne fera pas de restauration.

Quelle est la meilleure façon de traiter un tel problème?

La seule solution, je pense, est de renvoyer une erreur de ces fonctions et à l'intérieur de ces fonctions, ajoutez (trans_stat et trans_complete) Et s'il renvoie un test d'erreur, faites un $this->db->trans_rollback

ex:

    $this->db->trans_start();
     $result = $this->utils->insert_function($data);
     if($result === false){
       $this->db->trans_rollback();
     }
    $this->db->trans_complete();

Existe-t-il une meilleure façon de le faire?

Mise à jour 1:

Comme demandé, un échantillon de la fonction externe que j'appelle:

   // insert_function contains

    $rec = array(
        'numero' => $numero,
        'transaction_id' => $id,
        'debit' => $product_taxes['amount_without_taxes'],
        'date' => $data['date_transaction'],
    );
    $this->addExerciceAccountingRecords($rec);

  and addExerciceAccountingRecords contains

   function addExerciceAccountingRecords($records) {
    $this->db->insert('transactions_exercices', $records);
    }
32
Tarek

L'utilisation de transactions signifie des bases de données de support pour insérer des données en toute sécurité. Donc, dans Codeigniter, nous écrivons tous les fonctions liées à la base de données dans le modèle pas dans Controller.. Et dans votre deuxième code (qui ne fonctionne pas), vous avez pointé le modèle dessus (utils). Si simple, je suis sûr que cela ne fonctionnera pas. Parce que ce n'est pas une insertion de données avec le modèle et le contrôleur parallèle. La transaction doit être codée dans le modèle (j'écrirai dans le modèle dans ma réponse).


Chargez aussi ces trucs

  1. Bibliothèque de bases de données
  2. Classe de modèle
  3. Aide URL
  4. Session

Hypothèses

Dans votre code, vous avez utilisé $data et $test comme tableau. Je suppose donc qu'il y a deux tableaux pour insérer et mettre à jour des données.


Vos ensembles de données

$data = array(
   'title' => 'My title' ,
   'name' => 'My Name' ,
   'date' => 'My date'
);

$id = 007;
$test = array(
   'title' => $title,
   'name' => $name,
   'date' => $date
);

Votre code

$this->db->trans_start(); # Starting Transaction
$this->db->trans_strict(FALSE); # See Note 01. If you wish can remove as well 

$this->db->insert('table_name', $data); # Inserting data

# Updating data
$this->db->where('id', $id);
$this->db->update('table_name', $test); 

$this->db->trans_complete(); # Completing transaction

/*Optional*/

if ($this->db->trans_status() === FALSE) {
    # Something went wrong.
    $this->db->trans_rollback();
    return FALSE;
} 
else {
    # Everything is Perfect. 
    # Committing data to the database.
    $this->db->trans_commit();
    return TRUE;
}

Notes

  1. Par défaut, Codeigniter exécute toutes les transactions en mode strict. Lorsque le mode strict est activé , si vous exécutez plusieurs groupes de transactions, si un groupe échoue, tous les groupes seront annulés. Si strict désactivé , chaque groupe est traité indépendamment, ce qui signifie qu'une défaillance d'un groupe ne sera pas affecter tous les autres.
36
Abdulla Nilam

Ce que j'ai essayé était plus un truc, mais ça a marché pour moi.

$this->db->trans_begin();
  $rst1=  $this->utils->insert_function($data);
  $rst2 =  $this->utils->update_function2($test);
if($this->db->trans_status() === FALSE || !isset($rst1) || !isset($rst2)){
   $this->db->trans_rollback();
}else{
   $this->db->trans_commit();
}
5
Heshan Rajapaksha

Essayez cette procédure. Ça marche vraiment pour moi :)

$this->db->trans_start();
   $this->utils->insert_function($data);
   $this->utils->update_function2($test);
if($this->db->trans_status() === FALSE){
   $this->db->trans_rollback();
}else{
   $this->db->trans_complete();
}
3
Kahlil Vanz

Je soupçonne que le problème a à voir avec la façon dont CodeIgniter gère les objets.

Si vous accédez à la documentation CI sous la section "Création de bibliothèques" sur:
http://ellislab.com/codeigniter/user-guide/general/creating_libraries.html
et regardez la section relative à:

$CI =& get_instance();
$CI->load->helper('url');
$CI->load->library('session');
$CI->config->item('base_url');

Dans votre contrôleur principal, vous avez chargé/instancié la classe de base de données en utilisant le chargement automatique ou en chargeant explicitement la classe.

Vous allez ensuite de l'avant et ouvrez la transaction, puis vous accédez à vos fonctions de base de données via votre bibliothèque d'utilitaires.

Cependant, une fois que vous utilisez $this-db dans votre bibliothèque, vous accédez en réalité à une autre copie de l'instance de base de données, PAS à celle associée à votre transaction.

Pour accéder à la même instance, vous devez utiliser la fonction get_instance ().

Je pense que cela devrait régler votre problème. Votre style de codage d'origine pour séparer la fonction en différents modules est excellent. Vous devez simplement comprendre ces détails supplémentaires.

Veuillez essayer de confirmer que la restauration fonctionne comme prévu.

Le courage du code se compose du contrôleur suivant:

$this->db->trans_start();
$this->User_profile_m->create_new_user_profile();
$this->User_profile_m->create_new_user();
$this->db->trans_complete(); 

et un modèle simple user_profile_m pour gérer la persistance des données:

function create_new_user()
{
    $data['user_name_usr'] = $this->input->post('user_name');
    $data['create_date_usr'] = NULL;

    $this->db->insert('user_usr', $data);  
}

function create_new_user_profile()
{
    $data['user_name_pro'] = $this->input->post('user_name');
    $data['user_description_pro'] = $this->input->post('user_description');
    $data['create_date_pro'] = NULL;

    $this->db->insert('user_profile_pro', $data);  
}

Essentiellement, la démonstration essaie de faire deux insertions (une dans chacun des deux tableaux). Si un insert échoue, l'autre est annulé.

J'ai construit cela dans CodeIgniter 2.1.3 et je peux rendre les fichiers d'application disponibles via GitHub ou les compresser et vous les envoyer.

3
Marc Audet


Remarque: Assurez-vous d'utiliser $this->db->trans_begin() lors de l'exécution de transactions manuelles, PAS $this->db->trans_start().

$this -> db -> trans_begin(); 
$this -> utils -> insert_function ( $data );
$this -> utils -> update_function2 ( $test ); 
$this -> db -> trans_complete ();

Certifier au cas où utiliser MySql, utiliser au format InnoDb

3
Diego

Pour une insertion unique ou un enregistrement de mise à jour, vous pouvez utiliser la fonction affecte_rows

$this->db->insert('table_name', xss_clean($data));


//Check if there is a record affected
if($this->db->affected_rows() > 0)
              {
                  return true;
              }
              else
              { 
                  // if not succeeded
                  // check your last query 
                  die($this->db->last_query());
              }
0
bdalina