In my first table(ts_users) update opening user_opening_balance at the same time, I want to update that user_opening_balance in my second table(ts_voucher) column is voucher_amount. But in my second table table(ts_voucher) voucher_amount updates all columns amount.
My code:
public function updateConsignor($myData){
extract($myData);
$this->db->set('user_full_name' , $user_full_name);
$this->db->set('user_opening_balance' , $user_opening_balance);
$this->db->where('user_id', $user_id);
if($this->db->update('ts_users')){
$userId = $myData['user_id'];
$this->db->trans_begin();
$openingBalTrxn = array(
'voucher_amount' => $myData['user_opening_balance'],
);
$this->db->update('ts_voucher', $openingBalTrxn);
$this->db->where('voucher_person_account_id',$userId);
if ($this->db->trans_status() === false){
$this->db->trans_rollback();
return false;
}else{
$this->db->trans_commit();
return true;
}
return $query_result;
return true;
}else{
return false;
}
}
I am giving where condition
$this->db->update('ts_voucher', $openingBalTrxn);
$this->db->where('voucher_person_account_id',$userId);
for update one record it updates all voucher_amount column record
you need to run first your .where before your .update. See documentation here
$this->db->where('voucher_person_account_id',$userId);
$this->db->update('ts_voucher', $openingBalTrxn);
Your update query false. where clause first and other condition where first than update function call just copy this function and fix your problem.
public function updateConsignor($myData){
extract($myData);
$this->db->set('user_full_name' , $user_full_name);
$this->db->set('user_opening_balance' , $user_opening_balance);
$this->db->where('user_id', $user_id);
if($this->db->update('ts_users')){
$userId = $myData['user_id'];
$this->db->trans_begin();
$openingBalTrxn = array(
'voucher_amount' => $myData['user_opening_balance'],
);
$this->db->where('voucher_person_account_id',$userId);
$this->db->update('ts_voucher', $openingBalTrxn);
if ($this->db->trans_status() === false){
$this->db->trans_rollback();
return false;
}else{
$this->db->trans_commit();
return true;
}
return $query_result;
return true;
}else{
return false;
}
Your update operation is working before the 'where' condition has a chance to work. That's why it's updating all records. Simply put the where condition first, then update.
Related
I have read up on some stuff about transactions in Codeigniter. I have implemented them in my code and was wondering if someone could take a look and see if I am going in the right direction? So far I have not encountered any database issues but I want to make sure I have implemented transactions correctly.
In my code, I create the user details first and get the ID, then I insert that ID into the user accounts table.
Controller
if($this->form_validation->run()==false){
$this->index();
}else{
$password = md5($password);
$package = array(
'first_name'=>$first_name,
'last_name'=>$last_name,
'email'=>$email,
'client_id'=>$client_id,
'date_of_birth'=>$date_of_birth,
'phone_number'=>$phone_number,
'address'=>$address,
'country'=>$country,
'created_on'=>$this->get_date(),
'updated_on'=>$this->get_date()
);
if($this->AccountModel->user_account_exists($email)){
$this->session->set_flashdata('Error',"Account already exists");
redirect('/Register');
}else{
$this->db->trans_start();
$id = $this->AccountModel->create_person($package);
$error = $this->db->error();
$this->db->trans_complete();
$expiration_date = date('Y-m-d', strtotime($this->get_date() . "+1 month") );
if($this->db->trans_status()===false){
$this->index();
}else{
$account = array(
'username'=>$email,
'password'=>$password,
'user_type'=>'user',
'person_id'=>$id,
'is_active'=>true,
'created_on'=>$this->get_date(),
'updated_on'=>$this->get_date(),
'expires_on'=>$expiration_date,
'status'=>'active'
);
$this->db->trans_start();
$id = $this->AccountModel->create_user_account($account);
$error = $this->db->error();
$this->db->trans_complete();
if($this->db->trans_status()===false){
$this->index();
}else{
$this->session->set_flashdata('Success','Account has been created');
redirect('/Login');
}
}
}
if($error!=''){
$this->session->set_flashdata('Error',$error["message"]);
redirect('/Register');
}
}
Model
public function create_user_account($input){
$this->db->insert('user_accounts',$input);
return $this->db->insert_id();
}
public function create_person($input){
$this->db->insert('person',$input);
return $this->db->insert_id();
}
Hope someone can help me with this
The reason for transactions is to perform multiple db query operations and if any operations fail undo any that have already taken place.
You are only performing one operation within your transaction block so transactions are pointless. Other than that, you've got the idea.
In your case where you are only using db->insert() you can easily check the results and respond accordingly. db->insert() returns either true or false. If the return is false, get the error and set it into flashdata. Otherwise, go on with your work.
As #Topjka say, transactions should be in the model code.
Here's a sample model
class Some_model extends CI_Model
{
public function save_stuff($data)
{
//let's assume $data has values for two different tables
$newInfo = $data['newStuff'];
$updateInfo = $data['oldStuff'];
$this->db->trans_start();
$this->db->insert('other_table', $newInfo);
$this->db->update('one_table', $updateInfo);
$this->db->trans_complete();
if($this->db->trans_status() === FALSE)
{
$this->set_flash_error();
return FALSE;
}
return TRUE; //everything worked
}
public function set_flash_error()
{
$error = $this->db->error();
$this->session->set_flashdata('Error', $error["message"]);
}
}
Transactions are justified above because we do two db ops and if the either fails we don't want any changes to the db made.
Using the model/method in the controller
if($this->some_model->save_stuff($the_stuff) === FALSE)
{
redirect('/wherever');
}
//All OK, proceed
//do other controller things
I am trying to test transaction management in codeigniter. Below method is a function in a model class. If update_user_company_id method returns false, wrapper method save_user_and_company also returns. In this case, because the method returns before it reaches to
$this->db->trans_complete();
call, changes made by save_company and delete_company_requests methods are rolled back. This is what I want.
But what I want to learn is that instead of calling
$this->db->rollback();
I directly return from method.
Is this approach safe?
Is there a possibility that I may encounter a lock or some other problem in the future?
function save_user_and_company($user, $company_request) {
$result[STATU] = ERROR;
$this->db->trans_start();
$company = $this->companies_dao->save_company($company_request->company_name, $user->id);
if (!$company) {
$result[MESSAGE] = COMPANY_SAVE_ERROR;
return $result;
}
$company_request_result = $this->company_requests_model->delete_company_requests($company_request->id);
if (!$company_request_result) {
$result[MESSAGE] = COMPANY_REQUEST_DELETE_ERROR;
return $result;
}
$user_update = $this->users_dao->update_user_company_id($user->id, $company->id);
if (!$user_update) {
$result[MESSAGE] = USER_UPDATE_ERROR;
return $result;
}
$this->db->trans_complete();
$result[STATU] = SUCCESS;
$result[MESSAGE] = SUCCESSFUL;
return $result;
}
Thanks in advance!
Did you try like this....
Following code returns TRUE if transaction completes successfully.Otherwise it rollback your transaction and returns FALSE.Hope it will help you a lot..
function save_user_and_company($user, $company_request) {
$this->db->trans_begin(); //Begins your transaction
//Performs the transaction operations
$company = $this->companies_dao->save_company($company_request->company_name, $user->id);
$company_request_result = $this->company_requests_model->delete_company_requests($company_request->id);
$user_update = $this->users_dao->update_user_company_id($user->id, $company->id);
//Check whether transaction fails
if ($this->db->trans_status() === FALSE)
{
$this->db->trans_rollback();
$status = FALSE;
}
else
{
$this->db->trans_commit();
$status = TRUE;
}
return $status;
}
I use Codeigniter 3.0.6 to build a system.
Usually, I use affected_rows() to check whether my database is updated or not.
function update($id=0,$data=array())
{
$this->db->where($this->key, $id);
$this->db->update($this->table,$data);
if($this->db->affected_rows() > 0)return TRUE;
else return FALSE;
}
Problem is if no update found, it will return 0 as well. As I want to differentiate between Updated and No Update in my code, so i use this solution.
function update($id=0,$data=array())
{
$this->db->trans_start();
$this->db->where($this->key, $id);
$this->db->update($this->table,$data);
$this->db->trans_complete();
if ($this->db->affected_rows() > 0) {
return TRUE;
} else {
if ($this->db->trans_status() == FALSE) {
return FALSE;
}
return 'No Update';
}
}
But even after updated affected_rows always return int(0).
What's the reason? Thank you.
I'm also using CI 3.0.6 and affected_rows() gives back the correct amount of updated rows.
Can you do a test without the transactions. Something like this ?
function update($id)
{
$this->db->set('field_name', "new_value");
$this->db->where('id', $id);
$this->db->update('table_name');
$rows = $this->db->affected_rows();
return $rows;
}
Verify if a record is actually been updated in the database. You can check $rows for the update status.
if ($rows < 1) {
// no update
} else {
// updated
}
If you move $this->db->affected_rows() before the $this->db->trans_complete(); you will get expected count. Because affected_rows() check only the last statement which is $this->db->trans_complete(); in your problem it will be return 0 .
You can fix this by assign $this->db->affected_rows() to another variable before the $this->db->trans_complete(); and validate later.
function update($id=0,$data=array())
{
$this->db->trans_start();
$this->db->where($this->key, $id);
$this->db->update($this->table,$data);
$affected_rows = $this->db->affected_rows(); // moved to here from if condition
$this->db->trans_complete();
if ($affected_rows > 0) {
return TRUE;
} else {
if ($this->db->trans_status() == FALSE) {
return FALSE;
}
return 'No Update';
}
}
My code is liked this:
$this->db->trans_strict(FALSE); //close Strict Mode
$this->db->trans_begin();
$updateArr = array('name'=>'test', 'age'=>22);
$this->db->where('user_id', $user_id);
$this->db->limit(1);
$this->db->update('user_table', $updateArr);
$logArr = array('created'=>'2015-07-30', 'content'=>'test' );
$this->db->set($logArr)->insert('log_table');
if ($this->db->trans_status() === FALSE) {
$this->db->trans_rollback();
return false;
} else {
$this->db->trans_commit();
return true;
}
Does codeigniter transactions support activerecord?
When the first query return false, why does the second query return true ?
what am I doing wrong ? Please help me.
I use MySQL InnoDB
I am trying to update 3 tables using transaction if any one fails I need to roll back all the tables. For one table foreign key constraint fails but it does not return false statement instead showing console error of Database. Roll back is working. I include my code below. Kindly help.
The function below helps me to execute some queries
function funcname($val1,$val2,$val3){
$this->db->trans_start();//starting transaction
try { // trying to execute query
$this->db->query("UPDATE tab1 SET name = 1 WHERE id=".$val1);
$this->db->query("UPDATE school SET emp = 2 WHERE id=".$val2);
$this->db->query("UPDATE profile SET status = 4 WHERE id=".$val3);
$this->db->trans_complete();
return TRUE;
} catch (Exception $ex) { //exception roll back to original state
$this->db->trans_rollback();
return FALSE;
}
}
If you are using trans_start() and trans_complete() then you need not use a try catch statement. Your function will be like this.
function funcname($val1,$val2,$val3){
$this->db->trans_start();//starting transaction
$this->db->query("UPDATE tab1 SET name = 1 WHERE id=".$val1);
$this->db->query("UPDATE school SET emp = 2 WHERE id=".$val2);
$this->db->query("UPDATE profile SET status = 4 WHERE id=".$val3);
$this->db->trans_complete();
if ($this->db->trans_status() === FALSE)
{
return FALSE;
}
else
{
return TRUE;
}
}
In case you need to do it manually then use the code below
function funcname($val1,$val2,$val3){
$this->db->trans_begin();//starting transaction
$this->db->query("UPDATE tab1 SET name = 1 WHERE id=".$val1);
$this->db->query("UPDATE school SET emp = 2 WHERE id=".$val2);
$this->db->query("UPDATE profile SET status = 4 WHERE id=".$val3);
if ($this->db->trans_status() === FALSE)
{
$this->db->trans_rollback();
return FALSE;
}
else
{
$this->db->trans_commit();
return TRUE;
}
}
for more reference Transactions : CodeIgniter User Guide
I don't know how your db class works, but probably query return false on fails not throw Exception, so trans_complete() return false too, and then your function return TRUE