i have 3 sql operations which i thought put them in transaction would be a good practice because many times I faced some issues like first query runs and another fails so this is my code below
DB::beginTransaction();
try {
//update loan application
$loanApplication->status = 'DISBURSED';
$loanApplication->tenure = $offerDetails['tenure'];
$loanApplication->amount_offered = $offerDetails['loanAmount'];
$isUpdated = $loanApplication->update();
//create loan disbursal
LoanDisbursal::insertGetId([
'created_dt' => Carbon::now(),
'user_id' => $loanApplication->user_id,
'loan_account' => $loanApplication->application_id,
'gateway_alias' => $this->gatewayAlias,
'amount_approved' => $tradeLineInfo['loanAmount'],
'amount_disbursed' => $tradeLineInfo['disbursalAmount'],
'disbursed_on' => $tradeLineInfo['disbursalDate'],
'disbursal_ref' => $tradeLineInfo['disbursalId'],
'tenure' => $offerDetails['tenure'],
'wallet_credit_status' => 'DISBURSED',
]);
//create loan profile account
ProfilesHasAccount::insertGetId([
'user_id' => $loanApplication->user_id,
'gateway' => $this->gatewayAlias,
'account_segment' => 'BUSINESS',
'1account_type' => 'LOAN',
'created_dt' => Carbon::now(),
'status' => 'ACTIVE',
]);
} catch (\Throwable $th) {
dd(DB::rollback());
dd($th);
}
DB::commit();
Now here is the problem ,
while doing this operation my loan applicatiob got updated but there was problem on loanDisbursal entry so my catch block was invoked ,
there I used DB::rollback ,
so according to rollback,
loanApplication status should have change as it was earlier but it is 'DISBURSED' and no rollback happened in simple words
Also I have another project setup in my system in which everything is working as expected so what maybe the cause for this ,
I guess anything related to mysql configuration?
so I am just thinking why this happened ?
any ideas or suggestions , would be very helpful
OKAY I found the answer and the problem was my projects contains multiple datbases so I just had to show connections on transactions like this
DB::connection('ipay_app_loans__write')->beginTransaction();
DB::connection('ipay_app_loans__write')->rollBack();
DB::connection('ipay_app_loans__write')->commit();
That's it!!
Related
I'm currently using a package that logs activity via listening for model events based on changes made to them (create/update/delete). The code functions as expected locally though when it comes to writing feature tests, logging deletions fails. Here's the code:
it('should create a log when an admin is deleted', function() {
$administrator = Administrator::where('first_name', 'First Name')->first();
$administrator->delete();
//this passes
$this->assertSoftDeleted('administrators', [
'first_name' => $administrator->first_name,
'last_name' => $administrator->last_name,
'email' => $administrator->email,
]);
//this fails
$this->assertDatabaseHas('activity_log', [
'id' => 1,
'description' => 'admin deleted',
'subject_type' => 'App\\Models\\Administrator',
'subject_id' => $administrator->id,
'causer_type' => 'App\\Models\\Administrator',
'event' => 'deleted'
]);
In a create/update test, the second assertion passes because an activity_log is correctly created though on deletion tests, no log is created. The logging code for create/update is in their controllers/actions though for deletion, it's in the models. Is there a way for me to test that model events are correctly being fired correctly, if at all?
I got some duplicated row in my table but its impossible to insert via http request because I have validations for user balance that will change by every request and a request must be accepted by admin before another request. In this case The user had a balance of USD 1000. According to my code he can request once for USD 1000. but all of a sudden I got two rows at the same time in my database. how it may happen and what is the solution of this problem?
what I assume is when the 1st request arrived, the withdraw table was locked due to some other calculation so the balance was unchanged and the query was queued, as user got no response due to table lock he requested again then both requests were inserted!
please be informed that this is not happening everyday. It happens very rarely like 1 or 2 duplicate request in a year
public function withdrawBalance(Request $request)
{
if ($request->api_key == ApiKey()) {
$userInfo = User::find($request->user_id);
$checkPendingRequest = Withdraw::where(['user_id' => $request->user_id, 'status' => 0])->get(); //status column have default 0 until admin approval
if (count($checkPendingRequest) > 0) {
return response()->json(['status' => false, 'action' => 'already_pending_one', 'message' => 'Already have a pending request!.']);
}
$gs = GeneralSetting::first();
$balance = HoldingBalance($request->user_id)['withdrawble_balance'];
if ($request->amount > $balance) {
return response()->json(['status' => false, 'action' => 'insufficiant_balance', 'message' => 'Insufficient amount!.']);
}
if ($request->withdraw_method == 'bkash') {
$method_name = 'Digital';
} else {
$method_name = $request->withdraw_method;
}
Withdraw::create([
'branch_id' => $request->branch_id ?? 1,
'user_id' => $userInfo->id ?? null,
'purpose' => "$method_name Withdraw",
'withdraw_method' => $request->withdraw_method ?? null,
'withdraw_account' => $request->withdraw_account ?? null,
'amount' => round($request->amount, 2),
'payble_amount' => $request->amount,
'status' => 0
]);
return response()->json(['status' => true, 'action' => 'success', 'message' => 'Successfully submitted withdrawn request!.']);
} else {
return "Access Denied";
}
}
I guess any user double-click "Submit"
So 2 receipt requests arrived, each one performed a code level check and did not see that there was an execution of another query
I have not seen use of the table lock or transaction.
DB::beginTransaction();
check_if_data_already_exist();
add_data();
DB::commit();
This solution will greatly slow down the performance of your system.
The simplest solution is the option for each user to send one request at a given moment.
There are quite a few implementations of this problem.
In order to offer possible solutions we will need to get more information:
Is it possible to use the session?
Can the queue be used to enter the queries?
Maybe each user contains one row in the database and you can simply create a unique key at the database level
I a having a strange problem in laravel. I am using sweet alerts and laracasts flash package which work with sessions. they are working else where but when I insert a database entry using model I do not get any flash message in blade view. I am using model events when I don't use model events they work fine.
Can any body guide how can I resolve this. I do want to use model events too
in following snippet alert()->success in not working right after Message::create([]);
try
{
Message::create([
'customer_id' => $customer->id,
'sid' => time().bcrypt(time()),
'corr_id' => time().bcrypt(time()),
'sender' => $request['subject'],
'receiver' => $customer->contact,
'body' => $request['body'],
'place_holder' => 'inbox'
]);
alert()->success('Exception as Inbound Created For '.$customer->full_name,'Success')->autoclose(1500);
return redirect()->back();
}
catch (QueryException $e)
{
alert()->error($e->errorInfo[2],'Sorry')->autoclose(2000);
return redirect()->back();
}
This is hitting the database
$organization = factory(ilos\Models\Organization::class)->make([
"created_at" => Carbon::now()->subWeek(3),
"is_paid" => true,
"paid_until" => Carbon::now()->addWeek(1),
]);
This is not
$organization = factory(ilos\Models\Organization::class)->make([
"is_paid" => true,
"paid_until" => Carbon::now()->addWeek(1),
]);
Isn't make supposed to never hit the database?
how can I achieve the expected outcome?
I need to set the created_at to check if the organization is still in trial (this is for a unit test) and I don't want to touch the database.
Thanks for your help
I am using Laravel 4 and PHP to build a new application. It works fine on my dev server running PHP 5.4.x however my boss insist that it has to run version 5.3.2
I have spent the whole day fixing everything to work with 5.3.2 and almost have everything, so I thought, until I ran into an issue with the code below.
My problems start at this line...
DB::transaction(function($clock_in_webcam_image) use ($clock_in_webcam_image)
I believe this type of code might not work with this version of PHP? If that is the case, what are my options to run this same code or have it doing the same action?
Would appreciate any help with this. Very unfortunate that my boss told me straight out that no he will not allow us to update to a newer PHP so I am stuck in a hard spot right now
// Create a new time card record when a User Clocks In
public function createTimeCard($clock_in_webcam_image) {
// Create both Timecard and timecard record tables in a Transaction
DB::transaction(
function ($clock_in_webcam_image) use ($clock_in_webcam_image) {
$timeCard = DB::table('timeclock_timecard')->insertGetId(
array(
'user_id' => $this->user->user_id,
'clock_in_datetime' => $this->dateTime->format($this->dateFormat),
'clock_in_timestamp' => $this->dateTime->getTimestamp(),
'clock_in_webcam_image' => $clock_in_webcam_image
)
);
$timeCardPunchEntry = DB::table('timeclock_punch_entry')
->insertGetId(
array(
'timecard_id' => $timeCard,
'user_id' => $this->user->user_id,
'created_at_datetime' => $this->dateTime->format($this->dateFormat),
'created_at_timestamp' => $this->dateTime->getTimestamp(),
'clock_type' => 'clock_in',
'webcam_image' => $clock_in_webcam_image
)
);
return $timeCard;
}
);
}
UPDATE
In response to bansi's comment...is this what you mean to do...
DB::transaction(function() use($myModel){
$myModel->updateTable1();
$myModel->updateTable2();
})
Before PHP 5.4.0, you could not use $this inside an anonymous function. There is a simple workaround though where you can use the use construct to pass variables into the functions scope. Also, you are using the use construct incorrectly as $clock_in_webcam_image is not defined in the parent scope.
$user = $this->user;
$dateTime = $this->dateTime;
DB::transaction(function($clock_in_webcam_image) use ($user, $dateTime) {
// snip
array(
'user_id' => $user->user_id,
'clock_in_datetime' => $dateTime->format($this->dateFormat),
'clock_in_timestamp' => $dateTime->getTimestamp(),
'clock_in_webcam_image' => $clock_in_webcam_image
)
// snip
});
try this. please check you don't have another insertTimecard defined.
// Create a new time card record when a User Clocks In
public function createTimeCard($clock_in_webcam_image)
{
// Create both Timecard and timecard record tables in a Transaction
DB::transaction($this->insertTimecard($clock_in_webcam_image));
}
private function insertTimecard($clock_in_webcam_image)
{
$timeCard = DB::table('timeclock_timecard')->insertGetId(
array(
'user_id' => $this->user->user_id,
'clock_in_datetime' => $this->dateTime->format($this->dateFormat),
'clock_in_timestamp' => $this->dateTime->getTimestamp(),
'clock_in_webcam_image' => $clock_in_webcam_image
)
);
$timeCardPunchEntry = DB::table('timeclock_punch_entry')->insertGetId(
array(
'timecard_id' => $timeCard,
'user_id' => $this->user->user_id,
'created_at_datetime' => $this->dateTime->format($this->dateFormat),
'created_at_timestamp' => $this->dateTime->getTimestamp(),
'clock_type' => 'clock_in',
'webcam_image' => $clock_in_webcam_image
)
);
return $timeCard;
}