Mysql record missing when server lag - php

Customer use the app which create the order to deliver goods. In the database, it will generate the order_delivery table;
And then generate the goods_stock_vary_history table that record the changes of goods stock;
They are in one transaction.
The order_delivery has one goods_stock_vary_history.
But one day the customer created the order when server lag. And then he exist the app and create order again.
After a while, he say he cannot see his order.
I found the record of goods_stock_vary_history and its field order_delivery_id has value 2;
So I try to find order_delivery that primary key is 2.
And I cannot find it. There have primary keys 1 and 3 etc. The primary key is auto increment;
order_delivery has soft delete only; Nobody can delete that record.
The project use Laravel5.1 and the codes like below:
DB::beginTransaction();
foreach ($order_goods_matrix as $order_id => $goods_matrix) {
$goods_amount = OrderServices::countGoodsColorSizeMatrixAmount($goods_matrix);
if($goods_amount==0){
DB::rollback();
Redis::del($user_id . '_good_delever');
return $this->fail(self::ERROR_CODE, "Deliver Fail. The count cannot be zero");
}
if (intval($order_id) > 0 && $goods_amount > 0) {
$goods_matrix = json_encode($goods_matrix, true);
// Create order delivery
$ret = OrderServices::createDelivery($exist_flag, $user_id, $store_id, $order_id, $goods_matrix, OrderDelivery::DELIVERY_TYPE_COMMON, $created_at);
if ($ret['code'] < 0) {
DB::rollback();
Redis::del($user_id . '_good_delever');
return $this->fail(self::ERROR_CODE, "Deliver Fail" . $ret['msg']);
}
$get_history_id_arr[] = $ret['get_stock_histtory']['goods_stock_vary_history_id'];
}
}
$store_goods_sku = GoodsServiceV3::getGoodsSku($store_id);
foreach ($get_history_id_arr as $get_history_id_info) {
$get_history_detail[] = GoodsStockServiceV2::getGoodsStockVaryHistoryDetail($store_id, $get_history_id_info);
}
DB::commit();
in the function createDelivery:
$order_delivery = array();
$order_delivery['order_id'] = $order_id;
$order_delivery['customer_id'] = $order_base["buyer_user_id"];
$order_delivery['delivery_goods_color_size_matrix'] = $delivery_goods_color_size_matrix;
$order_delivery['delivery_goods_amount'] = $delivery_goods_amount;
$order_delivery['operate_user_id'] = $user_id;
$order_delivery['delivery_type'] = $delivery_type;
$order_delivery['exist_flag'] = $exist_flag;
$order_delivery['deliver_timestamp'] = $created_at;
$order_delivery_id = OrderDelivery::insertGetId($order_delivery);
if ($order_delivery_id == false) {
return array('code' => -3, 'msg' => 'Deliver fail');
}
$reverse_delivery_goods_color_size_matrix_array = GoodsStockServices::reverseGoodsColorSizeMatrix($delivery_goods_color_size_matrix_array);
// create goods_stock_vary_history
$get_stock_histtory = GoodsStockServices::addStockVariation($exist_flag, $user_id, $store_id, $reverse_delivery_goods_color_size_matrix_array, GoodsStockServices::STOCK_TYPE_DELIVER, GoodsStockServices::STOCK_TYPE_DELIVER_DEFAULT_REMARK, $order_delivery_id, null, $order_base["buyer_user_id"], $created_at);
return array('code' => 0, 'order_delivery_id' => $order_delivery_id, 'get_stock_histtory' => $get_stock_histtory);

I found the reason.
I created a trigger to track each order_delivery records after be deleted.
And then I found that order_delivery record is still missing, and the track table doesn't have any records.
So the missing order_delivery record is not deleted by someone or some method.
So I think the missing record is not missing, it just rollback, and another order_delivery inserted before it rollback, that make it like missing.
And then I try to log every database operation result for getting details.
I found there is a line not deal with the fail operation.
These code is written two years ago, the transaction part is smelly, you need to manually rollback the fail operation. and return fail message.
The better way is like this:
DB::beginTransaction();
try {
...
OrderServices::createDelivery($exist_flag, $user_id, $store_id, $order_id, $goods_matrix, OrderDelivery::DELIVERY_TYPE_COMMON, $created_at);
...
DB::commit();
} catch(\Throwable $e) {
DB::rollback();
throw $e;
}
After I change it, the missing record phenomenon not showing again.

Related

Database data field check before Data insertion

I have a data coming from the HTML Page. And i want to check whether the date and the place values already exists. If they exists, it should throw an error saying Data is already present, if those date and place data is not there it should allow the user to save it.
Here is the code which i have written to save it,
public function StoreSampling(Request $request)
{
$date = Carbon::createFromFormat('d-m-Y', $request->input('date'))->format('Y-m-d');
$doctorname = Input::get('doctorselected');
$product = Input::get('product');
$product= implode(',', $product);
$quantity = Input::get('qty');
$quantity =implode(',',$quantity);
$representativeid = Input::get('representativeid');
//Store all the parameters.
$samplingOrder = new SamplingOrder();
$samplingOrder->date = $date;
$samplingOrder->doctorselected = $doctorname;
$samplingOrder->products = $product;
$samplingOrder->quantity = $quantity;
$samplingOrder->representativeid = $representativeid;
$samplingOrder->save();
return redirect()->back()->with('success',true);
}
I searched some of the Stack over flow pages. And came across finding the existence through the ID And here is the sample,
$count = DB::table('teammembersall')
->where('TeamId', $teamNameSelectBoxInTeamMembers)
->where('UserId', $userNameSelectBoxInTeamMembers)
->count();
if ($count > 0){
// This user already in a team
//send error message
} else {
DB::table('teammembersall')->insert($data);
}
But i want to compare the date and the place. And if they are not present, i want to let the user to save it. Basically trying to stop the duplicate entries.
Please help me with this.
There are very good helper functions for this called firstOrNew and firstOrCreate, the latter will directly create it, while the first one you will need to explicitly call save. So I would go with the following:
$order = SamplingOrder::firstOrNew([
'date' => $date,
'place' => $place
], [
'doctorname' => Input::get('doctorselected'),
'product' => implode(',', Input::get('product')),
'quantity' => implode(',',Input::get('qty')),
'representativeid' => Input::get('representativeid')
]);
if($order->exists()) {
// throw error
return;
}
$order->save();
// success
You need to modify your query to something like this:
$userAlreadyInTeam = SamplingOrder::where('date', $date)
->where('place', $place) // I'm not sure what the attribute name is for this as not mentioned in question
// any other conditions
->exists();
if (userAlreadyInTeam) {
// Handle error
} else {
// Create
}
You do not need to use count() as your only trying to determine existence.
Also consider adding a multi column unique attribute to your database, to guarantee that you don't have a member with the same data and place.
The best way is to use the laravel unique validation on multiple columns. Take a look at this.
I'm presuming that id is your primary key and in the sampling_orders table. The validation rule looks like this:
'date' => ['unique:sampling_orders,date,'.$date.',NULL,id,place,'.$place]
p.s: I do not see any place input in your StoreSampling()

Laravel DB update exception

Im trying to get exception if update method failed i just check this try catch block it dont return any exception because this project id do not exist in my database i have only about hundred records.
try {
$project = DB::table('project')
->where('prj_id', '987654' )
->update([
'prj_status' => 'open',
'prj_updated_date' => Carbon::now()
]);
}catch(\Exception $e){
dd($e);
}
An update on none-existing row do not fail in SQL. If you run a query like UPDATE foo SET bar = 'foobar' WHERE 1 = 2; your database would be happy to do the job and report back 0 rows updated.
You will have to check the value of $project to see if the update did update any rows
If you're using Laravel 5, use the model to dictate what will be stored in the DB eventually.
So, using your project model, you'll have something like:
$project = Project::findOrFail('987654')
->update([
'prj_status' => 'open',
'prj_updated_date' => Carbon::now()
]);
You'll get a not found exception if the id of what you're looking for doesn't exist.
$projects_updated = DB::table('project')
->where('prj_id', '987654' )
->update([
'prj_status' => 'open',
'prj_updated_date' => Carbon::now()
]);
if($projects_updated) {
// n rows updated, do something
}
else {
// nothing updated
}

Magento how to detect changed fields only in admin section?

I need to insert some values to custom database table based on the values of changed custom field, if the specific custom field value (in a custom shipping method) had changed.I need to check this in my Observer.php event that I'm firing is admin_system_config_changed_section_carriers for getting values from the field and insert values to the table
is there any possible way to do this ?
EDIT:
here is my observer function
public function handle_adminSystemConfigChangedSection($observer){
$post = Mage::app()->getRequest()->getPost();
$firstBarcodeFlatrate = $post['groups']['flatrate']['fields']['barcode_start']['value'];
$lastBarcodeFlatrate = $post['groups']['flatrate']['fields']['barcode_end']['value'];
$flatrateRange = range($firstBarcodeFlatrate,$lastBarcodeFlatrate);
$shippingMethod = 'flatrate';
foreach($flatrateRange as $barcodes){
$insertData = array(
'barcode' => $barcodes,'shipping_method' => $shippingMethod,'status' => 1,
);
$model = Mage::getModel('customshippingmethods/customshippingmethods')->setData($insertData);
try {
$model->save();
} catch (Exception $e){
echo $e->getMessage();
}
}
as you can see above database query will update each time I save the configuration but I just need to run the query iff $firstBarcodeFlatrate value had changed
I would probably go with two options:
1. Cache the last value of $firstBarcodeFlatrate
$cacheId = 'first_barcode_flatrate_last_value';
$cache = Mage::app()->getCache();
$lastValue = $cache->load($cacheId);
if (!$lastValue) {
//We don't have cached last value, we need to run the query and cache it:
//Cache the value:
$cache->save($firstBarcodeFlatrate, $cacheId, array('first_barcode_flatrate_last_value'), null);
//Run the query here
} else {
//We have last value, we need to check if it has been changed:
if($lastValue != $firstBarcodeFlatrate) {
//Update the cached value:
$cache->save($firstBarcodeFlatrate, $cacheId, array('first_barcode_flatrate_last_value'), null);
//Run the query here.
}
}
Option 2 is to create another table with a single row and two fields or add another system config field that will store the last used value. Then before the running the query, you will check this value if it's different than $firstBarcodeFlatrate you will run the query, otherwise you won't, though I think the caching will do the job for you.

Custom Error in Active Record Codeigniter

I am using HMVC. My question is very simple. how we can catch the error in active records?
how we can return custom error to controller from model(active records)?
Actually, msn column is unique so, when i enter duplicate value then its show error like
Error Number: 1062
Duplicate entry '3696003284' for key 'msn'
but i want to show custom error instead of this.
my simple code is:
function insert_data($msn_number, $date_val, $min_val, $max_val, $avg_val,$counter)
{
for($i=0;$i<$counter;$i++)
{
$data = array(
'msn' => $msn_number[$i],
'date' => $date_val[$i],
'min_val' => $min_val[$i],
'max_val' => $max_val[$i],
'average' => $avg_val[$i]
);
$result = $this->db->insert('storage_data', $data);
if(!isset($result))
{
echo "custom Error";
}
}
}
}
i am wondering for the answer of this question please help me!
You may try this:
$result = $this->db->insert('storage_data', $data);
if (!$result) {
$data['msg'] = $this->db->_error_message();
$this->load->view('viw_db_error', $data); // Create a viw_db_error.php view
}
Make sure DB_DEBUG is set to FALSE in the application/config/database.php file, or execution will be halted if a mysql error occurs.
Update:
Alternatively you may query for that before every time you insert a new record but it would be very expensive because you are doing it inside a loop and it'll send many query/requests:
$q = $this->db->query("select msn from storage_data where msn = $msn_number[$i]");
if( $q->num_rows() ) {
// It already exists so maybe display a message
}

How to check records already exist in database when u save new record?

I want to add the new records in table if proudct_id and plan_id is already exist in same row then the error occur otherwise it save the record. I have written following lines of code but no success, if there is any help so please, thanks. I am doing it in cakephp
function admin_product_plan_add(){
$exists = $this->ProductPlan->find('all');
$this->set('exists',$exists);
foreach ($exists as $exists){
$plan_id = $exists['ProductPlan']['plan_id'];
$product_id = $exists['ProductPlan']['product_id'];
}
$conditions = array('ProductPlan.product_id' => $plan_id, 'ProductPlan.plan_id' => $product_id);
$data = $this->ProductPlan->find('all' , array('conditions'=>$conditions));
if (isset($data) && !empty($data))
{
echo '<p>User have already add this product plan!</p>';
}else{
if ($this->ProductPlan->save($this->data)){
$this->Session->setFlash('You have successfully add the product plan');
$this->redirect(array('controller' => 'productplans','action' => 'admin_product_plan_list'));
}
}
}
Use hasAny()
something like:
public function admin_product_plan_add(){
if($this->ProductPlan->hasAny(array("product_id" => $this->data['ProductPlan']['product_id'],'plan_id' => $this->data['ProductPlan']['plan_id']))){
// USER ALREADY HAVE THIS PRODUCTPLAN
} else {
//CREATE NEW PRODUCTPLAN
}
}
or something like that.
Hope this helps
One solution is to use a uniq index over these two rows. So when someone tries do add another row with the same data on these two rows, mysql throws an error and the data is not inserted.

Categories